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

后端 未结 2 588
日久生厌
日久生厌 2021-02-06 07:46

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 class

2条回答
  •  终归单人心
    2021-02-06 08:17

    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 _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(this, src, 1);
        }
    }
    
    internal class BindingEngine
    {
        private readonly T _destination;
        private readonly PropertyDescriptorCollection _sourceProperties;
        private readonly Dictionary _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();
    
            //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

提交回复
热议问题