观察集合(绑定到Datagrid) - 错误线程

时间:2011-11-08 15:56:22

标签: c# wpf multithreading binding collections

我有以下设置:

public class Monitor
{
    public ObservableCollection<People> listOfPeople = new ObservableCollection<People>();


    public dosomework() {
        Thread t = new ThreadStart(longwork);
        t.Start();
    }

   public longwork() {
        listOfPeople.Add(new People());
        Thread.Sleep(10000);

   }

}

public class People : INotifyPropertyChanged
{
    int _age;
    public int Age
    {
        get { return _age; }
        set
        {
            _age = value;
            Notify("Age");
        }
    }
}

public class UI : Window
{
    Monitor md = new Monitor();
}

我想将数据网格绑定到observable集合(datagrid.ItemSource = md.listOfPeople),但是,我遇到了线程错误。另外,如果我不对新线程进行长时间的工作,那么UI只会在longwork函数完成后更新。我认为绑定会避免这个问题。

任何帮助表示感谢。

3 个答案:

答案 0 :(得分:1)

绑定只是“其他代码监听更改”,因此线程仍然是一个问题。

通常的解决方法是在UI线程上执行添加到列表,因为这是Grid将要监听的位置,但如果针对单个元素运行,这将导致性能不佳。

最好将添加内容批量添加到后台线程上运行的临时列表中,并按间隔调用AddRange(每100项?)将该批次移动到UI集合上,以提供更好的响应和常规的DataGrid更新。

答案 1 :(得分:1)

正如其他人所说,如果你对UI以外的线程做任何工作,你必须调度到UI线程,以实际更新绑定到UI元素的任何元素。

在您的示例中,这将非常简单。只需将窗口的Dispatchermsdn)传递给Monitor,然后使用该代码进行相应的发送:

...
Monitor md = new Monitor(this.Dispatcher);
...
public Monitor(Dispatcher dispatcher)
{
     _dispatcher = dispatcher;
}
...
public longwork() {
    _dispatcher.BeginInvoke((Action)(()=>listOfPeople.Add(new People()));
    Thread.Sleep(10000);

}

您可以拨打Dispatcher.Invoke而不是Dispatcher.BeginInvoke,但如果您不关心结果并希望快速前进,BeginInvoke就是您的朋友。

答案 2 :(得分:0)

数据绑定数据网格订阅了CollectionChanged事件。根据我的经验,CollectionChanged事件是在任何导致集合更改的线程上引发的。在这种情况下,它不是UI线程。由于UI元素只能从UI线程修改,并且事件是在非UI线程上引发和处理的,因此您将获得“线程错误”。

如上所述,一个简单的解决方案是仅从UI线程修改ObservableCollection。

如果您使用的是WPF或Silverlight,则所有FrameworkElements都有一个Dispatcher属性,您可以使用该属性在UI线程上执行工作。另见:http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcherobject.aspx