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));
}
}
I took a similar approach to TheGateKeeper's eventual solution. However I was binding to many different objects. So I needed something a bit more generic. The solution was to create a wrapper that implemented also ICustomTypeDescriptor. In this way, I do not need to create wrapper properties for everything that can be displayed in the UI.
public class SynchronizedNotifyPropertyChanged<T> : INotifyPropertyChanged, ICustomTypeDescriptor
where T : INotifyPropertyChanged
{
private readonly T _source;
private readonly ISynchronizeInvoke _syncObject;
public SynchronizedNotifyPropertyChanged(T source, ISynchronizeInvoke syncObject)
{
_source = source;
_syncObject = syncObject;
_source.PropertyChanged += (sender, args) => OnPropertyChanged(args.PropertyName);
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged == null) return;
var handler = PropertyChanged;
_syncObject.BeginInvoke(handler, new object[] { this, new PropertyChangedEventArgs(propertyName) });
}
public T Source { get { return _source; }}
#region ICustomTypeDescriptor
public AttributeCollection GetAttributes()
{
return new AttributeCollection(null);
}
public string GetClassName()
{
return TypeDescriptor.GetClassName(typeof(T));
}
public string GetComponentName()
{
return TypeDescriptor.GetComponentName(typeof (T));
}
public TypeConverter GetConverter()
{
return TypeDescriptor.GetConverter(typeof (T));
}
public EventDescriptor GetDefaultEvent()
{
return TypeDescriptor.GetDefaultEvent(typeof (T));
}
public PropertyDescriptor GetDefaultProperty()
{
return TypeDescriptor.GetDefaultProperty(typeof(T));
}
public object GetEditor(Type editorBaseType)
{
return TypeDescriptor.GetEditor(typeof (T), editorBaseType);
}
public EventDescriptorCollection GetEvents()
{
return TypeDescriptor.GetEvents(typeof(T));
}
public EventDescriptorCollection GetEvents(Attribute[] attributes)
{
return TypeDescriptor.GetEvents(typeof (T), attributes);
}
public PropertyDescriptorCollection GetProperties()
{
return TypeDescriptor.GetProperties(typeof (T));
}
public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
return TypeDescriptor.GetProperties(typeof(T), attributes);
}
public object GetPropertyOwner(PropertyDescriptor pd)
{
return _source;
}
#endregion ICustomTypeDescriptor
}
Then in the Ui, I bind to this wrapper using something like:
private void CreateBindings()
{
if (_model == null) return;
var threadSafeModel = new SynchronizedNotifyPropertyChanged<MyViewModel>(_model, this);
directiveLabel.DataBindings.Add("Text", threadSafeModel, "DirectiveText", false, DataSourceUpdateMode.OnPropertyChanged);
}
MyViewModel has a "DirectiveText" property and implements INotifyPropertyChanged with no special consideration to threading or to the view classes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With