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

后端 未结 2 586
日久生厌
日久生厌 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:10

    I believe I only have access to the the vanilla .Net framework

    The reality is that data binding is used in UI. So, if anybody talks about data binding, then he automatically implies "data binding in [UI Framework name]".

    You may consider object-to-object mapping instead of data binding.

    0 讨论(0)
  • 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<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

    0 讨论(0)
提交回复
热议问题