INotifyPropertyChanged的会导致跨线程错误 [英] INotifyPropertyChanged causes cross-thread error

查看:574
本文介绍了INotifyPropertyChanged的会导致跨线程错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面是我的scenarion:



我必须绑定到一个一个的BindingList GridControl。在我做的第一件事是建立一个工作线程,并直接访问的BindingList,但这是抛出一个检测到跨线程操作,所以我跟着这里的指南:



http://www.devexpress.com/Support/Center/p/AK2981的.aspx



通过克隆原来的BindingList到工作线程和不断变化的那一个,我得到了预期的效果。不过,我最近implemeneted的INotifyPropertyChanged的成举行入的BindingList对象,我又开始得到错误。



我的猜测是,在GridView仍然听该INotifyPropertyChanged的从对象



我怎样才能解决这个问题。



我的类:

 公共类代理:INotifyPropertyChanged的
{
公共事件PropertyChangedEventHandler的PropertyChanged;

保护无效OnPropertyChanged(字符串名称)
{
PropertyChangedEventHandler处理器=的PropertyChanged;
如果(处理!= NULL)
{
处理器(这一点,新PropertyChangedEventArgs(名));
}
}


解决方案

如果你是从UI线程之外操纵UI(如从辅助线程),那么你需要重新加入UI线程。你可以通过调用调用的UI控件做到这一点。如果这是通过使用需要,您可以测试 InvokeRequired



通常使用的模式是这样的:

 公共无效ChangeText(字符串文本)
{
如果(this.InvokeRequired)
{
this.Invoke(新动作(()=> ChangeText(文本)));
}
,否则
{
label.Text =文本;
}
}

在您的情况下,UI被操纵结果的 INotifyPropertyChanged的,所以你需要确保,要么你总是修改UI线程上的实体(使用上述技术),或使用的generic异步INotifyPropertyChanged的帮手。这是围绕着项目的包装所束缚。它采用上述技术,保证了UI线程上的 ChangeProperty 事件触发。



下面是一个非常粗略的例子对于实体类的代理。这确保了属性更改事件重新加入到UI线程,并保持实体本身不变。很显然,你可能会想实现这个更一般采用DynamicObject例如

 公共类NotificationHelper:INotifyPropertyChanged的
{
公共事件PropertyChangedEventHandler的PropertyChanged;

私人只读ISynchronizeInvoke invokeDelegate;
私人只读实体实体;

公共NotificationHelper(ISynchronizeInvoke invokeDelegate,实​​体实体)
{
this.invokeDelegate = invokeDelegate;
this.entity =实体;

entity.PropertyChanged + = OnPropertyChanged;
}

公共字符串名称
{
{返回entity.Name; }
}

私人无效OnPropertyChanged(对象发件人,PropertyChangedEventArgs E)
{
如果(的PropertyChanged!= NULL)
{
如果(invokeDelegate.InvokeRequired)
{
invokeDelegate.Invoke(新PropertyChangedEventHandler(OnPropertyChanged),
新的[] {发送,E});
的回报;
}
的PropertyChanged(这一点,E);
}
}
}


Here is my scenarion:

I have a GridControl bound to a BindingList. At first what I was doing was creating a worker thread and access the BindingList directly, but this was throwing a "Cross-thread operation detected", so I followed the guide here:

http://www.devexpress.com/Support/Center/p/AK2981.aspx

By cloning the original BindingList into the worker thread and changing that one, I got the desired effect. However, I recently implemeneted the INotifyPropertyChanged into the object that is held into the BindingList, and I started getting the error again.

My guess is that the GridView is still listening to the INotifyPropertyChanged from the object.

How can I fix this?

My class:

public class Proxy : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }

解决方案

If you are manipulating the UI from outside of the UI thread (such as from a worker thread), then you need to rejoin the UI thread. You can do this by calling Invoke on the UI control. You can test if this is required by using InvokeRequired.

The pattern typically used is this:

public void ChangeText(string text)
{
   if(this.InvokeRequired)
   {
      this.Invoke(new Action(() => ChangeText(text)));
   }
   else
   {
      label.Text = text;  
   }
}

In your case the UI is being manipulated as a result of INotifyPropertyChanged, so you need to make sure that either you always modify your entity on the UI thread (using the above technique), or use a generic asynchronous INotifyPropertyChanged helper. This is a wrapper around the item being bound. It uses the above technique to ensure the ChangeProperty event fires on the UI thread.

Here's a very crude example of a proxy for an Entity class. This ensures that the property change event rejoins the UI thread, and keeps the entity itself unmodified. Obviously you'll probably want to implement this more generically using DynamicObject for instance.

public class NotificationHelper : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private readonly ISynchronizeInvoke invokeDelegate;
    private readonly Entity entity;

    public NotificationHelper(ISynchronizeInvoke invokeDelegate, Entity entity)
    {
       this.invokeDelegate = invokeDelegate;
       this.entity = entity;

       entity.PropertyChanged += OnPropertyChanged;
    }

    public string Name
    {
       get { return entity.Name; }
    }

    private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (PropertyChanged != null)
        {
           if (invokeDelegate.InvokeRequired)
           {
               invokeDelegate.Invoke(new PropertyChangedEventHandler(OnPropertyChanged),
                                     new[] { sender, e });
               return;
           }
           PropertyChanged(this, e);
        }
     }
 }

这篇关于INotifyPropertyChanged的会导致跨线程错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆