I intend to use data binding between a few of my classes. In other words, I am not binding values between a model class and the UI, but to bind variables between different classes.
I have read about data binding in C# on several places, but most of them are referring to binding between Windows Form and a source object.
I am still new to C#. This is how I understand what I should do:
First, for my source object, say has a class name of DataObject
. The source object has to implement a INotifyPropertyChange
interface, and then trigger the event whenever the property, health
, is set to change. I have no problem with this.
Now, suppose I have a target object called CharacterClass
. life
is a property in CharacterClass
, and is also the target property that I want to bind to the source object's health
property.
How can I bind the two properties together (both one-way and two-way) in code with only just the ordinary .NET framework?
A bit of background information on why I ask this question:
Just in case you think this is a duplicated question, it's not. I have searched through SE. The other questions on databinding in code are in the context of WPF or XAML, which is not for me. I have also read several articles on MSDN and it seems that I could create a Binding
object, and then bind the source and target via BindingOperations.SetBinding()
. However, the Binding
class seems to be part of the WPF library under the namespace of System.Windows.Data.Binding
. Although I am using C#, I doubt I would have the luxury to access to WPF libraries because I'm mainly using C# as only a scripting language within Unity3D. I believe I only have access to the the vanilla .Net framework. But, I am not very sure about this because I am still new to C#.
Data binding is the process that establishes a connection between the app UI and the data it displays. If the binding has the correct settings and the data provides the proper notifications, when the data changes its value, the elements that are bound to the data reflect changes automatically.
The ngModel directive with [] syntax is used for one-way data binding. [ngModel] binds a value to a property to UI control.
In C#, early binding is a process in which a variable is assigned to a specific type of object during its declaration to create an early-bound object. This contrasts the late-bound object process, where an object type is revealed at the time of instantiation.
Though there is a lot of support for bindings that is tightly coupled with the UI framework being used, you can still easily write your own binding framework.
Here is a POC which implements one-way binding between properties of two objects.
Note: This is just one of the possible ways, a POC at best (may need fine-tuning for high performance/production scenario) and uses .Net 2.0 classes and interfaces with no dependency on any UI framework (the 'vanilla' .net framework in your words :)). Once you have understood this, you can easily extend this to support 2-way binding as well
class Program
{
public static void Main()
{
Source src = new Source();
Destination dst = new Destination(src);
dst.Name = "Destination";
dst.MyValue = -100;
src.Value = 50; //changes MyValue as well
src.Value = 45; //changes MyValue as well
Console.ReadLine();
}
}
//A way to provide source property to destination property
//mapping to the binding engine. Any other way can be used as well
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
internal class BindToAttribute : Attribute
{
public string PropertyName
{
get;
private set;
}
//Allows binding of different properties to different sources
public int SourceId
{
get;
private set;
}
public BindToAttribute(string propertyName, int sourceId)
{
PropertyName = propertyName;
SourceId = sourceId;
}
}
//INotifyPropertyChanged, so that binding engine knows when source gets updated
internal class Source : INotifyPropertyChanged
{
private int _value;
public int Value
{
get
{
return _value;
}
set
{
if (_value != value)
{
_value = value;
Console.WriteLine("Value is now: " + _value);
OnPropertyChanged("Value");
}
}
}
void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
internal class Destination
{
private BindingEngine<Destination> _binder;
private int _myValue;
[BindTo("Value", 1)]
public int MyValue
{
get
{
return _myValue;
}
set
{
_myValue = value;
Console.WriteLine("My Value is now: " + _myValue);
}
}
//No mapping defined for this property, hence it is not bound
private string _name;
public string Name
{
get
{
return _name;
}
set
{
_name = value;
Console.WriteLine("Name is now: " + _name);
}
}
public Destination(Source src)
{
//Binder for Source no 1
_binder = new BindingEngine<Destination>(this, src, 1);
}
}
internal class BindingEngine<T>
{
private readonly T _destination;
private readonly PropertyDescriptorCollection _sourceProperties;
private readonly Dictionary<string, PropertyDescriptor> _srcToDestMapping;
public BindingEngine(T destination, INotifyPropertyChanged source, int srcId)
{
_destination = destination;
//Get a list of destination properties
PropertyDescriptorCollection destinationProperties = TypeDescriptor.GetProperties(destination);
//Get a list of source properties
_sourceProperties = TypeDescriptor.GetProperties(source);
//This is the source property to destination property mapping
_srcToDestMapping = new Dictionary<string, PropertyDescriptor>();
//listen for INotifyPropertyChanged event on the source
source.PropertyChanged += SourcePropertyChanged;
foreach (PropertyDescriptor property in destinationProperties)
{
//Prepare the mapping.
//Add those properties for which binding has been defined
var attribute = (BindToAttribute)property.Attributes[typeof(BindToAttribute)];
if (attribute != null && attribute.SourceId == srcId)
{
_srcToDestMapping[attribute.PropertyName] = property;
}
}
}
void SourcePropertyChanged(object sender, PropertyChangedEventArgs args)
{
if (_srcToDestMapping.ContainsKey(args.PropertyName))
{
//Get the destination property from mapping and update it
_srcToDestMapping[args.PropertyName].SetValue(_destination, _sourceProperties[args.PropertyName].GetValue(sender));
}
}
}
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