Wpf .NET4.0中的异步代码
我在WPF应用程序中运行以下代码: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
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应用程序执行此操作的情况。谢谢