我的问题是:如何超越编写用于对各种控件(没有内置DataSource属性的控件)进行数据绑定的技术的自定义实现,将每种可能的数据类型绑定到简单的属性……如下面的代码中所描述和演示的…以获得更强大的解决方案,而该解决方案将与绑定是绑定到字符串,int还是其他类型无关.
我的猜测是:这将涉及反思.但是,我被困在那一点上.我正在寻找下一个“方向”的战略建议,提示,线索,而不是完整的代码答案,但是我当然感谢所有答复,并且如果您张贴代码作为答复,我一定会研究代码!马克·克利夫顿(Marc Clifton)在2005年关于CodeProject Simple Databinding的文章:似乎演示了一种基于反射的方法:但是,老实说,我并没有真正理解他的代码,就.NET而言,2005年已经很久了.
背景技术:部分响应于各种SO问题和答案,例如:Update Usercontrol on Three Forms:我已经开发出一种成功的技术,可以将各种控件的文本属性同时数据绑定到Public类中定义的一个源.还可以使用定义一个扩展方法和两个公共方法的静态类“抽象”绑定过程的某些细节.
我已验证“ MainForm”上控件上的TextBoxes,MainForm上UserControl上的TextBoxes和“独立”打开的第二个Form(即form2.Parent == null)上的TextBox都可以正确更新(即,两个-way绑定有效)来自“ DataSource等效”公共类.更改一:全部更改.
代码:此类的实例将提供目标属性(theText)进行数据绑定:
public class TextDataBinder
{
public event PropertyChangedEventHandler PropertyChanged;
private string _theText;
public string theText
{
get { return _theText; }
// note : if 'setter is declared 'internal : blocks
// auto-updating when run-time user modifies consumers
// but will still allow update via code
set
{
_theText = value;
OnPropertyChanged(new PropertyChangedEventArgs("theText"));
}
}
protected void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, e);
}
}
}
代码:此静态类可隐藏某些绑定过程的复杂性,并允许轻松绑定到多个控件:
public static class TextBindingExtender
{
public static TextDataBinder CurrentDataSource;
public static void SetCurrentDataSource(TextDataBinder newCurrentDataSource)
{
CurrentDataSource = newCurrentDataSource;
}
// extension method for Control
public static void AddTextBinding(this Control theControl, string controlPropertyName, string targetPropertyName)
{
theControl.DataBindings.Add(controlPropertyName, CurrentDataSource, targetPropertyName, false, DataSourceUpdateMode.OnPropertyChanged);
}
// bind to all Controls in a List<Control>
public static void AddTextBindings(List<Control> theControls, string controlPropertyName, string targetPropertyName)
{
foreach (Control theControl in theControls)
{
theControl.AddTextBinding(controlPropertyName, targetPropertyName);
}
}
}
以上类的使用方式(在Form Load事件中):
// create a new TextDataBinder
TextBindingExtender.CurrentDataSource = new TextDataBinder();
// bind to multiple textboxes, label, on a UserControl, on another Form, etc.
TextBindingExtender.AddTextBindings(new List<Control> { textBox1, textBox2, userControl11.tb, label1, instanceOfForm2.tb }, "Text", "theText");
// test assigning some initial text to the bound property
TextBindingExtender.CurrentDataSource.theText = "some initial text";
解决方法:
这真的取决于您要做什么;但最终,常见的数据绑定(对于简单属性,需要手动完成)包括:
>获得财产;最好通过TypeDescriptor.GetProperties(obj)[propName]来给您一个抽象(PropertyDescriptor)
>询问属性是否为只读(.IsReadOnly)
>获取(或设置)值(.GetValue()、. SetValue())
>要求它提供一个转换器以格式化/解析值(.Converter,.ConvertFromString()、. ConvertToString()),这是关键,这意味着您不必担心数据类型是什么
>要求标题(.DisplayName,如果为空/空则为.Name)
>询问它是否支持特定于属性的通知(.SupportsChangeEvents)
>要求它添加/删除更改处理程序(.AddValueChanged()、. RemoveValueChanged())
>您可能还想查看对象是否支持集中式通知(查找INotifyPropertyChanged)
如果您可能绑定到列表而不是单个对象:
-列表可能在IListSource后面抽象
-该列表可能具有自定义属性,因此请检查ITypedList
-否则,确定项目的类型并使用TypeDescriptor.GetProperties(type)
-您需要考虑“货币管理器”(即,绑定到同一列表的所有事物都应该始终指向列表中的同一记录)
还有一些类似ICustomTypeDescriptor和TypeDescriptionProvider的东西需要考虑,但是大多数时候TypeDescriptor会自动为您处理.
如您所见-有很多事情要考虑!许多工作……您不必做的一件事就是反思.这是在PropertyDescriptor之后抽象的.这是因为并非所有数据都是静态类型的.考虑一下DataTable-列(映射到可绑定数据属性)在编译时不是固定的,因此反射是不合适的.同样,其他一些类型也具有自定义的“属性包”实现. PropertyDescriptor允许您的代码以相同方式处理动态(非4.0含义)和反射属性.它也可以很好地与“ HyperDescriptor”(另一个属性自定义)之类的东西配合使用.