扩展一个解决方案,简单地绑定到一个'Text属性到多个控件来处理绑定到任何Type? [英] Extending a solution for simple binding to a 'Text property to multiple Controls to handle binding to any Type?
问题描述
我的猜测是:这将涉及反射;但是,我坚持在这一点上。我正在寻找战略建议,哪个方向移动下一个,提示,线索,而不是一个完整的代码答案,但我当然感谢所有的回复,我一定要学习代码,如果你发送代码回复! Marc Clifton 2005年关于CodeProject的文章简单数据绑定:似乎表明了一种基于反射的方法但是,老实说,我真的不在乎他的代码,而在.NET方面,2005是一个很久以前的。
背景:部分地针对各种SO问题和答案,例如: Update UserControl on Three Forms :我已经发展了一种成功的技术,用于将各种控件的文本属性数据绑定到公共类中定义的一个源代码;也可以使用定义一个扩展方法的静态类和两个公共方法抽象一些绑定进程的细节。
我已经验证了MainForm中的控件上的TextBox,MainForm上的UserControl上的TextBox,第二个窗体上的TextBox独立(即, ,form2.Parent == null)所有从DataSource等效公共类正确更新(即双向绑定有效)。更改一个:全部更改。
代码:此类的一个实例将提供数据绑定的目标属性(theText):
public class TextDataBinder
{
public event PropertyChangedEventHandler PropertyChanged;
私人字符串_theText;
public string theText
{
get {return _theText;
//注意:如果'setter被声明'内部:块
//自动更新运行时用户修改消费者
//但仍然允许更新通过代码
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;
}
//控件的扩展方法
public static void AddTextBinding(this Control theControl,string controlPropertyName,string targetPropertyName)
{
theControl.DataBindings .Add(controlPropertyName,CurrentDataSource,targetPropertyName,false,DataSourceUpdateMode.OnPropertyChanged);
}
//绑定到List中的所有控件< Control>
public static void AddTextBindings(List< Control> theControls,string controlPropertyName,string targetPropertyName)
{
foreach(Control theControl in theControls)
{
theControl.AddTextBinding controlPropertyName,targetPropertyName);
}
}
}
如何使用上述类(在表单加载事件中):
//创建一个新的TextDataBinder
TextBindingExtender.CurrentDataSource = new TextDataBinder() ;
//绑定到多个文本框,标签,UserControl,另一个窗体等上。
TextBindingExtender.AddTextBindings(new List< Control> {textBox1,textBox2,userControl11.tb,label1 ,instanceOfForm2.tb},Text,theText);
//测试将一些初始文本分配给绑定属性
TextBindingExtender.CurrentDataSource.theText =一些初始文本;
这真的取决于你想做什么;但是最终通常的数据绑定(对于简单的属性,手动完成)包括:
- 获取属性;最好通过
TypeDescriptor.GetProperties(obj)[propName]
,给你一个抽象(PropertyDescriptor
) - 询问该属性是否为只读(
.IsReadOnly
) - 获取(或设置)值(
.GetValue()
,.SetValue()
) - 对于转换器格式化/解析值(
.Converter
,.ConvertFromString()
,.ConvertToString()
)这是一个关键位,这意味着您不必担心数据类型的 - 要求它的标题(
.DisplayName
或.Name
如果它为空/ null) - 询问是否支持特定于属性的通知(
.SupportsChangeEvents
) - 要求它添加/删除更改处理程序(
.AddValueChanged()
,.RemoveValueChanged()
) - 您可能还需要查看对象是否支持centr通知(查找
INotifyPropertyChanged
)
如果您可能绑定到列表而不是单个对象:
- 列表可能会在 IListSource
后面被抽象 - 列表可能具有自定义属性,因此请检查 ITypedList
- 否则,标识项目的类型
并使用 TypeDescriptor.GetProperties(type)
- 你需要考虑一个货币管理者(即所有绑定到同一个列表的东西都应该一直指向列表中的同一条记录)
还有一些类似于 ICustomTypeDescriptor
和 TypeDescriptionProvider
要考虑,但大部分时间 TypeDescriptor
会自动处理这个。 / p>
你可以看到 - 很多事情要考虑!许多工作...你不要要做的一件事是反思;这是在 PropertyDescriptor
之后抽象出来的。原因在于并非所有数据都是静态类型的;考虑 DataTable
- 列(映射到可绑定的数据属性)在编译时不是固定的,因此反射是不合适的。同样,一些其他类型具有定制的属性包实现。 PropertyDescriptor
可以让您的代码处理动态(不是4.0感觉)和反射属性相同。它也可以很好地与HyperDescriptor,另一个属性定制。
My question is : how to move beyond writing a custom implementation of a technique for databinding multiple controls (controls without built-in DataSource properties), for each possible type of data, to simple properties ... as described and demonstrated in code that follows ... to achieve a more poweful solution that will be independent of whether the binding is to a string, or an int, or other types.
My guess is: this will involve reflection; but, I'm stuck at that point. I'm looking for strategic advice on which "direction" to move next, hints, clues, not a complete code answer, but of course I appreciate all responses, and I'll sure study code if you post code in reply ! Marc Clifton's 2005 article on CodeProject Simple Databinding: appears to demonstrate a reflection based approach: but, honestly, I do not really grok his code, and, in terms of .NET, 2005 is a long time ago.
Background: Partly in response to various SO questions and answers, like: Update Usercontrol on Three Forms: I've evolved a successful technique for databinding text properties of various controls simultaneously to one source defined in a Public class; also been able to "abstract" some of the details of the binding process using a static class that defines one extension method, and two public methods.
I've verifed that TextBoxes on Controls in a "MainForm," TextBoxes on a UserControl on the MainForm, and a TextBox on a second Form opened "independently" (i.e., form2.Parent == null) all update properly (i.e., two-way binding is in effect) from the "DataSource equivalent" public class. Change one: change all.
Code: an instance of this class will supply the target property (theText) for databinding:
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);
}
}
}
Code: this static class enables hiding some of the binding process complexity, and allows easy binding to multiple controls:
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);
}
}
}
How the above classes are used (in a Form Load event) :
// 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";
It really depends what you want to do; but ultimately common data-binding (for simple properties, done manually) consists of:
- obtaining a property; preferably via
TypeDescriptor.GetProperties(obj)[propName]
, giving you an abstraction (PropertyDescriptor
) - asking the property if it is read-only (
.IsReadOnly
) - obtain (or set) the value (
.GetValue()
,.SetValue()
) - asking it for a converter to format / parse the value (
.Converter
,.ConvertFromString()
,.ConvertToString()
) THIS is a key bit that means you don't have to worry about what the data type is - asking it for the caption (
.DisplayName
, or.Name
if that it empty/null) - asking it if it supports property-specific notification (
.SupportsChangeEvents
) - asking it to add/remove a change handler (
.AddValueChanged()
,.RemoveValueChanged()
) - you might also want to look at whether the object supports centralised notification (look for
INotifyPropertyChanged
)
If you might be binding to a list rather than a single object:
- the list might be abstracted behind IListSource
- the list might have custom properties, so check for ITypedList
- otherwise, identify the Type
of the items and use TypeDescriptor.GetProperties(type)
- you need to consider a "currency manager" (i.e. should all the things bound to the same list be pointing to the same record in the list all the time)
There are also things like ICustomTypeDescriptor
and TypeDescriptionProvider
to consider, but most of the time TypeDescriptor
handles this for you automatically.
As you can see - lots of things to think about! Lots of work... the one thing that you don't have to do is reflection; this is abstracted behind PropertyDescriptor
. The reason for this is that not all data is static-typed; think about DataTable
- the columns (which map to bindable data properties) are not fixed at compile-time, so reflection isn't appropriate. Likewise, some other types have custom "property bag" implementations. PropertyDescriptor
lets your code handle either dynamic (not in the 4.0 sense) and reflective properties identically. It also works nicely with things like "HyperDescriptor", another property customisation.
这篇关于扩展一个解决方案,简单地绑定到一个'Text属性到多个控件来处理绑定到任何Type?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!