Wpf .NET4.0中的异步代码

Wpf .NET4.0中的异步代码,wpf,.net-4.0,Wpf,.net 4.0,我在WPF应用程序中运行以下代码: public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); this.Loaded += new RoutedEventHandler(MainWindow_Loaded); } void MainWindow_Loaded(object sender, RoutedEventAr

我在WPF应用程序中运行以下代码:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
    }

    void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
        object obj = new object();
        Collection.Add(obj);
        Collection.CollectionChanged += new NotifyCollectionChangedEventHandler(delegate(object sender2, NotifyCollectionChangedEventArgs e2)
        {
            if (Collection.Count == 0)
                App.Current.MainWindow.Close();
        });

        Task.Factory.StartNew(() =>
            {
                //Do long running process
                Collection.Remove(obj); //this errors out
            });
    }

    private ObservableCollection<object> Collection = new ObservableCollection<object>();
}
我得到错误System.InvalidOperationException:调用线程无法访问此对象,因为它是另一个线程拥有的


我的印象是Task.Factory.StartNew将异步任务排队,因此线程应该是相同的,不是吗?

Task.Factory.StartNew在默认的TaskScheduler中执行您的操作,因此它将在线程池中运行

ObservableCollection不是线程安全的。这意味着在UI线程中不会执行CollectionChanged处理程序,该处理程序在UI控件App.Current.MainWindow.Close上执行操作,因为正在任务的操作中执行集合修改,从而导致您看到的错误

如果只需要与处理程序中的UI交互,则可以使用dispatcher:

Collection.CollectionChanged += new NotifyCollectionChangedEventHandler(delegate(object sender2, NotifyCollectionChangedEventArgs e2)
        {
            if (Collection.Count == 0)
                this.Dispatcher.BeginInvoke((Action)(()=> App.Current.MainWindow.Close()));
        });

如果需要绑定,请考虑使用线程安全实现。请参见

Task.Factory.StartNew在默认TaskScheduler中执行您的操作,因此它将在线程池中运行

ObservableCollection不是线程安全的。这意味着在UI线程中不会执行CollectionChanged处理程序,该处理程序在UI控件App.Current.MainWindow.Close上执行操作,因为正在任务的操作中执行集合修改,从而导致您看到的错误

如果只需要与处理程序中的UI交互,则可以使用dispatcher:

Collection.CollectionChanged += new NotifyCollectionChangedEventHandler(delegate(object sender2, NotifyCollectionChangedEventArgs e2)
        {
            if (Collection.Count == 0)
                this.Dispatcher.BeginInvoke((Action)(()=> App.Current.MainWindow.Close()));
        });

如果需要绑定,请考虑使用线程安全实现。请参见

以补充Arthur的答案,在我的实际应用程序中,不是上面的示例代码,我需要从MvvmLight视图模型执行此操作。要从ViewModel访问dispatcher,请执行以下操作:

在应用程序内部,添加以下内容:

static App()
{
    DispatcherHelper.Initialize();
}
然后,由于ViewModel没有对Dispatcher的引用,因此不调用this.Dispatcher,而是执行以下操作:

DispatcherHelper.UIDispatcher.BeginInvoke((Action)(() => App.Current.MainWindow.Close()));

为了补充Arthur的答案,在我的实际应用程序中,不是上面的示例代码,我需要从MvvmLight视图模型中执行此操作。要从ViewModel访问dispatcher,请执行以下操作:

在应用程序内部,添加以下内容:

static App()
{
    DispatcherHelper.Initialize();
}
然后,由于ViewModel没有对Dispatcher的引用,因此不调用this.Dispatcher,而是执行以下操作:

DispatcherHelper.UIDispatcher.BeginInvoke((Action)(() => App.Current.MainWindow.Close()));

我添加了一个答案,以反映从MVVMLight应用程序执行此操作的情况。谢谢我添加了一个答案,以反映从MVVMLight应用程序执行此操作的情况。谢谢