使用任务库加载ICollectionView

时间:2014-07-14 13:11:04

标签: wpf multithreading icollectionview

我遇到以下问题: 如果我将一个简单的列表加载到绑定在我的wpf列表框中的ICollectionView中,那么就像我预期的那样引发CurrentChanged事件:

List<int> l = new List<int>();
l.Add(1);
l.Add(2);
MyCollection = CollectionViewSource.GetDefaultView(l);
MyCollection.CurrentChanged += MyCollection_CurrentChanged; // ok, it's raised

然而,想象一下我将数据加载到另一个线程中,然后,我想要相同的行为,即提升currentChanged事件,但它不起作用:

 List<int> l = new List<int>();
            Task.Factory.StartNew(() =>
            {
                l.Add(1);
                l.Add(2);
            })
            .ContinueWith((r) => 
                {

                    MyCollectio = CollectionViewSource.GetDefaultView(l);
                    MyCollectio.CurrentChanged += MyCollectio_CurrentChanged; // ko, it isn't raised.

                }, TaskScheduler.FromCurrentSynchronizationContext());

请注意,我使用TaskScheduler.FromCurrentSynchronizationContext()来处理UI线程,但它不起作用。我也没试过Application.Current.Dispatcher.Invoke。

1 个答案:

答案 0 :(得分:0)

我认为根本原因在于你的xaml。

如果您使用的<ListBox />或其他ItemsControl来自Selector,请尝试将IsSynchronizedWithCurrentItem设置为 True ,例如这样:

<ListBox ItemsSource="{Binding MyCollectio}"
         IsSynchronizedWithCurrentItem="True"
         />

我已经尝试过这种方法,无论有没有TPL Task

,这都可以

在MainWindow.xaml.cs中我有这个(尝试一下,xaml应该包含上面提到的 ListBox ):

public MainWindow()
{
    InitializeComponent();

    MyVM con = new MyVM();
    DataContext = con;
    List<int> l = new List<int>();
    Task.Factory.StartNew(() =>
    {
        l.Add(1);
        l.Add(2);
        l.Add(3);
        l.Add(4);
        l.Add(5);
        l.Add(6);
    })
    .ContinueWith((r) =>
    {

        con.MyCollectio = CollectionViewSource.GetDefaultView(l);
        con.MyCollectio.CurrentChanged += MyCollectio_CurrentChanged;
    }, TaskScheduler.FromCurrentSynchronizationContext());
}

void MyCollectio_CurrentChanged(object sender, EventArgs e)
{
    MessageBox.Show("Curren really changed!!!");
}

...

public class MyVM : ViewModelBase
{
    public ICollectionView MyCollectio
    {
        get
        {
            return _MyCollectio;
        }

        set
        {
            _MyCollectio = value;
            RaisePropertyChanged("MyCollectio");
        }
    }
    private ICollectionView _MyCollectio;
}

...

public class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public void RaisePropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }
}