1

我在 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排队了一个异步任务,所以线程应该是一样的,不是吗?

4

2 回答 2

3

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

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

如果您只需要在处理程序中与 UI 交互,则可以使用调度程序:

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

如果您需要绑定到它,请考虑使用线程安全的实现。看到这个。

于 2012-11-29T18:58:26.930 回答
1

只是为了添加 Arthur 的答案,在我的真实应用程序(不是上面的示例代码)中,我需要从 MvvmLight 视图模型中执行此操作。要从 ViewModel 访问调度程序:

在 App 内部,添加以下内容:

static App()
{
    DispatcherHelper.Initialize();
}

然后不是调用this.Dispatcher,因为 ViewModel 没有对 Dispatcher 的引用,所以以下将起作用:

DispatcherHelper.UIDispatcher.BeginInvoke((Action)(() => App.Current.MainWindow.Close()));
于 2012-11-29T19:21:24.303 回答