Winforms中的两种方式DataBinding

Chr*_*387 4 c#

我正在学习数据绑定,我有一个带有一个属性的类,然后我有另一个带有组合框和2个值"1和2"的类,我已经用属性创建了我的类的数组对象,所以当组合框有1我的文本框会给它一个类[0] .property的值,相反,如果我有2这个发生在类[1] .property这里是代码,所以你会更好地理解:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WindowsFormsApplication1
{
    struct Class1
    {
        public string pollo { get; set; }
    }
}
Run Code Online (Sandbox Code Playgroud)

我的第二堂课:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        Class1[] prova = new Class1[2];
        int a;

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            a = Convert.ToInt32(comboBox1.SelectedItem) - 1;
            prova[a].pollo = textBox1.Text;
        }

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            a = Convert.ToInt32(comboBox1.SelectedItem) - 1;
            textBox1.DataBindings.Add("Text", prova[a], "pollo", false, DataSourceUpdateMode.OnPropertyChanged);
            textBox1.DataBindings.Clear();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            comboBox1.SelectedIndex = 0;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

一切正常,但这是一种单向数据绑定实际上我必须使用单击按钮设置属性,在这种情况下,没有这样的区别:

textBox1.DataBindings.Add("Text", prova[a], "pollo", false, DataSourceUpdateMode.OnPropertyChanged);
Run Code Online (Sandbox Code Playgroud)

textBox1 = prova[a];
Run Code Online (Sandbox Code Playgroud)

那么为什么要使用数据绑定?我的意思是我怎么能用两种方式来自动设置我的属性?

谢谢

Pet*_*iho 6

您的代码中存在一些问题,导致绑定无法正常工作,从而模糊了实用性.

首先,要明确:正在设置的绑定是在当前选定的Class1对象和Text属性之间TextBox.您正在使用ComboBox更改当前所选对象来绑定TextBox到.我假设你已经意识到这一点,但我想确定一下.

现在,就代码中的问题而言......

  1. 最严重的问题是您的数据类型Class1被声明为a struct而不是a class.的struct类型是一个值类型,每当代码需要一个对象引用,该值的副本意味着盒装(存储在的一个实例object).理解这个盒装值是一个副本是非常重要的.它与您存储在数组中的值完全断开,因此即使成功设置了绑定,对象的更改也不会反映在从数组中检索对象值的代码中的其他位置.

  2. 几乎同样严重的是你在设置后立即清除绑定.这完全否定了数据绑定的要点,即允许框架根据另一个对象的更改自动更新属性值.所以是的,在你的代码示例中,set-binding-then-clear-binding操作与简单地直接设置属性之间几乎没有任何区别.

这两个问题中的任何一个都足以阻止数据绑定以有用的方式工作.但还有第三个问题......

  1. 您的Class1类型未实现属性更改事件.在Winforms中,您可以实现具有名称的事件polloChanged(即属性名称,后跟单词Changed,拼写和大写完全相同),或者通过实现INotifyPropertyChanged接口.如果没有这些机制,双向数据绑定就无法工作,因为框架无法知道属性值何时发生了变化.(讽刺的是,是什么的工作是目标到源绑定...也就是说,因为TextBox类实现的TextChanged情况下,数据绑定能够设置源属性当目标属性更改,但它不会去其他办法).

下面是一个代码版本,它充分利用数据绑定,Class1正确实现(作为一个实际的class,具有必要的polloChanged事件),正确配置绑定,并将对象的pollo属性绑定到一个,Label以便明确对象的pollo属性是更新:

class Class1
{
    private string _pollo = "";
    public string pollo
    {
        get { return _pollo; }
        set
        {
            _pollo = value;
            Raise(polloChanged, this);
        }
    }

    private static void Raise(EventHandler handler, object sender)
    {
        if (handler != null)
        {
            handler(sender, EventArgs.Empty);
        }
    }

    public event EventHandler polloChanged;
}
Run Code Online (Sandbox Code Playgroud)


public partial class Form1 : Form
{
    private Class1[] _prova =
    {
        new Class1 { pollo = "<not set 1>" },
        new Class1 { pollo = "<not set 2>" }
    };

    public Form1()
    {
        InitializeComponent();

        comboBox1.SelectedIndex = 0;
    }

    private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
    {
        // Obviously in a more complicated data binding scenario, you might
        // want to be more specific about which binding(s) is(are) being
        // removed, rather than just clearing everything.
        textBox1.DataBindings.Clear();
        label1.DataBindings.Clear();

        // If the user edits the text in the TextBox, the pollo property
        // of the currently-selected object will be immediately updated
        textBox1.DataBindings.Add("Text", _prova[comboBox1.SelectedIndex],
            "pollo", false, DataSourceUpdateMode.OnPropertyChanged);

        // We're never going to change the label1.Text property directly,
        // so the binding doesn't ever need to update the source property.
        label1.DataBindings.Add("Text", _prova[comboBox1.SelectedIndex],
            "pollo", false, DataSourceUpdateMode.Never);
    }
}
Run Code Online (Sandbox Code Playgroud)

我假设您可以在表单中推断出必要的textBox1,comboBox1label1控件,而不是让我发布所有的Designer代码.


最后,如果你更喜欢这种INotifyPropertyChanged方法,这就是Class1使用这种技术的样子:

class Class1 : INotifyPropertyChanged
{
    private string _pollo = "";
    public string pollo
    {
        get { return _pollo; }
        set
        {
            _pollo = value;
            OnPropertyChanged();
        }
    }

    private void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;

        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}
Run Code Online (Sandbox Code Playgroud)