Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I do data binding in code with C#?

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#.

like image 923
Carven Avatar asked Oct 18 '12 05:10

Carven


People also ask

What is data binding in 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.

Which of the following syntax is used for data binding?

The ngModel directive with [] syntax is used for one-way data binding. [ngModel] binds a value to a property to UI control.

What does binding mean in C#?

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.


1 Answers

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));
        }
    }
}

enter image description here

like image 163
Amit Mittal Avatar answered Oct 21 '22 20:10

Amit Mittal