【问题标题】:How can I do data binding in code with C#?如何使用 C# 在代码中进行数据绑定?
【发布时间】:2012-10-08 12:07:40
【问题描述】:

我打算在我的几个类之间使用数据绑定。换句话说,我不是在模型类和 UI 之间绑定值,而是在不同类之间绑定变量。

我在几个地方读到过 C# 中的数据绑定,但大部分都是指 Windows 窗体和源对象之间的绑定。

我还是 C# 的新手。这就是我理解我应该做什么的方式:

首先,对于我的源对象,假设有一个类名DataObject。源对象必须实现INotifyPropertyChange 接口,然后在属性health 设置为更改时触发事件。我对此没有任何问题。

现在,假设我有一个名为CharacterClass目标对象lifeCharacterClass 中的一个属性,也是我要绑定到源对象的health 属性的目标属性

如何仅使用普通的 .NET 框架在代码中将两个属性绑定在一起(单向和双向)?

关于我为什么问这个问题的一些背景信息:

万一您认为这是一个重复的问题,事实并非如此。我已经通过 SE 进行了搜索。关于代码中数据绑定的其他问题是在 WPF 或 XAML 的上下文中,这不适合我。我也看过 MSDN 上的几篇文章,看来我可以创建一个Binding 对象,然后通过BindingOperations.SetBinding() 绑定源和目标。但是,Binding 类似乎是 System.Windows.Data.Binding 命名空间下的 WPF 库的一部分。尽管我使用的是 C#,但我怀疑我是否有机会访问 WPF 库,因为我主要使用 C# 作为 Unity3D 中的一种脚本语言。我相信我只能访问 vanilla .Net 框架。但是,我对此不太确定,因为我还是 C# 的新手。

【问题讨论】:

    标签: c# data-binding


    【解决方案1】:

    我相信我只能访问 vanilla .Net 框架

    现实情况是数据绑定在 UI 中使用。因此,如果有人谈论数据绑定,那么他会自动暗示“[UI 框架名称] 中的数据绑定”。

    您可以考虑对象到对象的映射而不是数据绑定。

    【讨论】:

    • 实际上,是的,关于 UI 的数据绑定是正确的。在我的情况下,我正在构建一个 UI,但不是使用 Windows 窗体。我所指的所有那些目标对象主要是我的UI类。所以我希望的是一种“自定义”的排序数据绑定技术,我可以在我自己的非 WinForm UI 上实现。
    • @xEnOn:主要问题是绑定引擎与 UI 框架内部紧密耦合。例如,WPF 绑定使用依赖属性,因此,如果您想使用它,您必须将您的 UI 类编写为 DependencyObject 后代。我认为,您应该编写自己的绑定引擎。
    • 我明白了。谢谢!看起来我没有运气使用 C# 现有的数据绑定引擎。 :( 我想我必须研究如何编写自己的绑定引擎。也许我会在这里提出一个新问题,以了解数据绑定引擎如何在后台工作,让自己了解如何编写数据绑定引擎。非常感谢,丹尼斯。:)
    • 对不起,但这个答案实际上并没有试图回答这个问题。另一个答案是。
    【解决方案2】:

    尽管有很多与正在使用的 UI 框架紧密耦合的绑定支持,但您仍然可以轻松编写自己的绑定框架。

    这是一个 POC,它实现了两个对象的属性之间的单向绑定。

    注意:这只是可能的方法之一,充其量是 POC(可能需要针对高性能/生产场景进行微调)并使用 .Net 2.0 类和接口,不依赖于任何 UI 框架('vanilla ' .net 框架用你的话来说:))。一旦你理解了这一点,你就可以轻松地扩展它以支持 2-way 绑定

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-21
      • 1970-01-01
      • 2016-04-14
      相关资源
      最近更新 更多