扩展一个解决方案,简单地绑定到一个'Text属性到多个控件来处理绑定到任何Type? [英] Extending a solution for simple binding to a 'Text property to multiple Controls to handle binding to any Type?

查看:273
本文介绍了扩展一个解决方案,简单地绑定到一个'Text属性到多个控件来处理绑定到任何Type?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题是:如何超越编写用于数据绑定多个控件(无内置DataSource属性的控件)的技术的自定义实现,对于每种可能的数据类型 em>,到简单属性... ,如以下中的代码所述和演示,以实现更加强大的解决方案,这将独立于绑定是否是字符串或int,或其他类型。



我的猜测是:这将涉及反射;但是,我坚持在这一点上。我正在寻找战略建议,哪个方向移动下一个,提示,线索,而不是一个完整的代码答案,但我当然感谢所有的回复,我一定要学习代码,如果你发送代码回复! 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屋!

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