To create a Dynamic Object which you can use for two-way data-binding to Windows Forms control, you should derive from DynamicObject and also implement ICustomTypeDescriptor and INotifyPropertyChanged interface.
- DynamicObject: Deriving from
DynamicObjectprovides a solution for specifying dynamic behavior at run time. - ICustomTypeDescriptor:
ICustomTypeDescriptoris responsible to return metadata about the object including a list of properties. SinceDynamicObjectdoesn’t have real properties, you should return a list of customPropertyDescriptorobjects which allow the consumer to get/set value of the property. - INotifyPropertyChanged:
INotifyPropertyChangedis responsible for raisingPropertyChangedevent. It’s a key point in two-way data-binding.
When setting up data binding to a property, framework invokes AddValueChanged method of the PropertyDescriptor of that property. To provide two-way data binding, your property descriptor should override that method and subscribe for PropertyChanged event of the component and call OnValueChanged method of the property descriptor:
void PropertyChanged(object sender, EventArgs e)
{
OnValueChanged(sender, e);
}
public override void AddValueChanged(object component, EventHandler handler)
{
base.AddValueChanged(component, handler);
((INotifyPropertyChanged)component).PropertyChanged += PropertyChanged;
}
public override void RemoveValueChanged(object component, EventHandler handler)
{
base.RemoveValueChanged(component, handler);
((INotifyPropertyChanged)component).PropertyChanged -= PropertyChanged;
}
How to update controls using data-binding when the dynamic object updates in a non-UI thread?
To update the controls using data-binding when the dynamic object updates in a non-UI thread , you can use either of the following options:
- Option 1 You can change
MyCustomObjectimplementation a bit toInvokethe event in UI thread when required by passing an instance ofISynchronizeInvoke. - Option 2 You can use the instance of
ISynchronizeInvoketoInvokethe code in UI thread, in the other thread which you are going to update the object.
Option 1
To implement the first solution, you can add the following constructor to MyCustomObject class to accept and instance of ISynchronizeInvoke:
ISynchronizeInvoke syncronzeInvoke;
public MyCustomObject(ISynchronizeInvoke value = null)
{
syncronzeInvoke = value;
}
Then in OnPropertyChanged, use ISyncronzeInvoke.InvokeRequired to check if invoke is required and then if invoke is required, use ISyncronzeInvoke.Invoke to invoke the event in the UI thread:
private void OnPropertyChanged(string name)
{
var handler = PropertyChanged;
if (handler != null)
{
if (syncronzeInvoke != null && syncronzeInvoke.InvokeRequired)
syncronzeInvoke.Invoke(handler, new object[]
{ this, new PropertyChangedEventArgs(name) });
else
handler(this, new PropertyChangedEventArgs(name));
}
}
Then when creating the object, pass this as an instance of ISynchronizeInvoke to MyCustomObject:
dynamic data;
private void Form1_Load(object sender, EventArgs e)
{
data = new MyCustomObject(this);
//...
}
Then when changing data, simply change data in the other thread:
private void button2_Click(object sender, EventArgs e)
{
Task.Run(() =>
{
data.StringProperty = "Another Text";
data.BooleanProperty = true;
data.DateTimeProperty = DateTime.Now.AddYears(30);
data.IntegerProperty = 300;
});
}
Using this solution, the thread doesn’t need to know anything about the ISynchronizeInvoke. It just updates MyCustomObject.
Option 2
To use the second solution, you can simply use Invoke in the other thread to change object properties:
private void button2_Click(object sender, EventArgs e)
{
Task.Run(()=> {
this.Invoke(new Action(() =>
{
data.StringProperty = "Another Text";
data.BooleanProperty = true;
data.DateTimeProperty = DateTime.Now.AddYears(30);
data.IntegerProperty = 300;
}));
});
}
In this solution, the thread should care about UI thread and should consider changing the dynamic object using ISyncronzeInvoke.Invoke.
Example
In the example, I’ve created an implementation of the DynamicObject which you can simply add properties to it and use for two-way data-binding in Windows Forms. You can find a working implementation in the following repository or download it. The implementation contains option 1 to support multi thread environments.

Notes
- The post is written to extend and support the answer which I posted for this question in stackoverflow: Dynamic object two way data binding and its follow up questions which I received.