C# Winforms中的两种数据绑定方式

C# Winforms中的两种数据绑定方式,c#,C#,我正在学习数据绑定,我有一个具有一个属性的类,然后我有另一个具有combobox和2个值“1和2”的类,我已使用该属性创建了我的类的数组对象,因此当combobox具有1时,我的文本框将给它一个值给类[0]。属性,而如果我有2个,则会发生这种情况类[1].property以下是代码,以便您更好地理解: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System

我正在学习数据绑定,我有一个具有一个属性的类,然后我有另一个具有combobox和2个值“1和2”的类,我已使用该属性创建了我的类的数组对象,因此当combobox具有1时,我的文本框将给它一个值给类[0]。属性,而如果我有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; }
    }
}
我的第二节课:

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;
        }
    }
}
一切正常,但这是一种单向数据绑定。事实上,我必须使用click按钮设置属性,在这种情况下,以下两者之间没有任何区别:

textBox1.DataBindings.Add("Text", prova[a], "pollo", false, DataSourceUpdateMode.OnPropertyChanged);

那么为什么要使用数据绑定呢?我的意思是,我怎样才能使它两种方式,以便自动设置我的属性


谢谢

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

首先,需要明确的是:正在设置的绑定位于当前选定的
Class1
对象和
TextBox
Text
属性之间。您正在使用
组合框
更改要将
文本框
绑定到的当前选定对象。我想你知道,但我想确定一下

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

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

  • 同样严重的是,设置绑定后立即清除绑定。这完全否定了数据绑定的意义,即允许框架根据另一个对象中的更改自动更新属性值。因此,是的,在您的代码示例中,设置绑定然后清除绑定操作与直接设置属性之间没有任何区别

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

  • 您的
    Class1
    类型未实现属性更改事件。在Winforms中,您可以实现名为
    polloChanged
    (即属性名称,后跟单词
    Changed
    ,拼写和大写与之完全相同)的事件,也可以实现
    INotifyPropertyChanged
    接口。如果没有这两种机制,双向数据绑定就无法工作,因为框架无法知道属性的值何时发生了更改。(具有讽刺意味的是,真正起作用的是目标到源的绑定……也就是说,因为
    TextBox
    类实现了
    TextChanged
    事件,所以当目标属性更改时,数据绑定能够设置源属性。但它不会走另一条路)
  • 这是一个充分利用数据绑定的代码版本,它正确地实现了
    Class1
    (作为实际的
    class
    ,并带有必要的
    polloChanged
    事件),正确地配置了绑定,并将对象的
    pollo
    属性绑定到
    标签
    ,以便明确对象的
    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;
    }
    

    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;
    }
    
    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);
        }
    }
    
    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;
    }