如何使用C#在代码中进行数据绑定? [英] How can I do data binding in code with C#?
问题描述
我已经在几个地方阅读了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屋!