如何使用C#在代码中进行数据绑定? [英] How can I do data binding in code with C#?

查看:131
本文介绍了如何使用C#在代码中进行数据绑定?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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



我还是C#的新手。这是我如何理解我应该做什么:



首先,对于我的源代码对象,说有一个类名为 DataObject 。源对象必须实现一个 INotifyPropertyChange 接口,然后每当属性 health 设置为更改。我没有问题。



现在,假设我有一个目标对象称为 CharacterClass 生活 CharacterClass 中的一个属性,也是我想要的目标属性绑定到源对象的健康属性。



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



有一些背景信息,为什么我问这个问题: / p>

如果你认为这是一个重复的问题,那不是。我通过SE搜索。代码中数据绑定的其他问题是WPF或XAML的上下文,这不适用于我。我也在MSDN上阅读了几篇文章,似乎我可以创建一个绑定对象,然后通过绑定源和目标BindingOperations.SetBinding( )。但是, Binding 类似乎是 System.Windows.Data.Binding 的命名空间下的WPF库的一部分。虽然我正在使用C#,但我怀疑我会拥有访问WPF库的奢侈,因为我主要使用C#作为Unity3D中的一种脚本语言。我相信我只能访问香草.Net框架。但是,我不太清楚这一点,因为我还是C#的新手。

解决方案

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



这是一个在两个对象的属性之间实现单向绑定的POC。注意:这只是可能的方法之一,POC最好(可能需要微调高性能/生产场景),并使用.Net 2.0类和接口不依赖于任何UI框架(您的话中的vanilla.net框架))。一旦了解了这一点,您可以轻松地将其扩展为支持双向绑定

  class Program 
{
public static void Main()
{
源src = new Source();
目标dst = new目的地(src);
dst.Name =目的地;
dst.MyValue = -100;
src.Value = 50; //更改MyValue以及
src.Value = 45; //更改MyValue以及
Console.ReadLine();
}
}

//提供源属性到目标属性的方法
//映射到绑定引擎。可以使用任何其他方式
[AttributeUsage(AttributeTargets.Property,AllowMultiple = false)]
内部类BindToAttribute:属性
{
public string PropertyName
{
get;
私人集;
}

//允许将不同的属性绑定到不同的源
public int SourceId
{
get;
私人集;
}

public BindToAttribute(string propertyName,int sourceId)
{
PropertyName = propertyName;
SourceId = sourceId;
}
}

// INotifyPropertyChanged,所以绑定引擎知道什么时候更新
内部类来源: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;
}

内部类目标
{
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);
}
}

//没有为此属性定义映射,因此不绑定
private string _name;
public string Name
{
get
{
return _name;
}
set
{
_name = value;
Console.WriteLine(Name is now:+ _name);
}
}

public目的地(源src)
{
//源代码Binder B
_binder = new BindingEngine< Destination> ;(这个,src,1);
}
}

内部类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;

//获取目标属性列表
PropertyDescriptorCollection destinationProperties = TypeDescriptor.GetProperties(destination);

//获取源属性列表
_sourceProperties = TypeDescriptor.GetProperties(source);

//这是目标属性映射的源属性
_srcToDestMapping = new Dictionary< string,PropertyDescriptor>();

//在源代码上收听INotifyPropertyChanged事件
source.PropertyChanged + = SourcePropertyChanged;

foreach(destinationProperties中的PropertyDescriptor属性)
{
//准备映射。
//添加已定义绑定的那些属性
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 )
{
//从映射获取目标属性并更新它
_srcToDestMapping [args.PropertyName] .SetValue(_destination,_sourceProperties [args.PropertyName] .GetValue(sender));
}
}
}


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

解决方案

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

这篇关于如何使用C#在代码中进行数据绑定?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆