将控件绑定到对象vs DataRow

时间:2019-01-18 10:43:38

标签: c# .net winforms data-binding

我写了一些示例代码来演示我的问题。一个绑定到对象,另一个绑定到DataRow:

绑定到DataRow示例:

namespace WindowsFormsApplication1
{
    public partial class frmBindExample : Form
    {
        public frmBindExample()
        {
            InitializeComponent();
            InitForm();
        }



        private void InitForm()
        {
            //;; Init the list
            DataTable dt = new DataTable();
            dt.Columns.Add(new DataColumn("Id"));
            dt.Columns.Add(new DataColumn("Name"));
            dt.Rows.Add(new string[] { "5476", "Smith" });
            dt.Rows.Add(new string[] { "5477", "Marlin" });


            Label label1 = new Label() { Top = 130, Left = 10, Text = "Id of Smith is:" };
            this.Controls.Add(label1);

            //;; Bind two direction with TextBox. 
            TextBox textbox1 = new TextBox() { Top = 130, Left = 130, Width = 100 };
            this.Controls.Add(textbox1);
            textbox1.DataBindings.Add("Text", dt.Rows[0], "Id");


            //;; The binding system respose changing property value
            Button button1 = new Button() { Top = 160, Left = 10, Width = 200, Text = "Set Id=99 Directly by property" };
            this.Controls.Add(button1);
            button1.Click += (s, e) =>
            {
                dt.Rows[0]["Id"] = "99";
            };

            DataGridView dg = new DataGridView() { Top = 200, Left = 10 };
            this.Controls.Add(dg);
            dg.DataSource = dt;
        }


    }
}

它看起来像:

enter image description here

如您所见,与TextBox的绑定在下一个示例中不起作用。但是,当我通过按下按钮更新字段时,数据网格立即刷新:

enter image description here

好吧,现在看看如果我绑定对象,那是什么麻麻:

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 frmBindExample : Form
    {
        public frmBindExample()
        {
            InitializeComponent();
            InitForm();
        }


        private void InitForm()
        {
            //;; Init the list
            List<Person> lst = new List<Person>();
            lst.Add(new Person() { Id = "5476", Name = "Smith" });
            lst.Add(new Person() { Id = "5477", Name = "Marlin" });


            Label label1 = new Label() { Top = 130, Left = 10, Text = "Id of Smith is:" };
            this.Controls.Add(label1);

            //;; Bind two direction with TextBox. 
            TextBox textbox1 = new TextBox() { Top = 130, Left = 130, Width = 100 };
            this.Controls.Add(textbox1);
            textbox1.DataBindings.Add("Text", lst[0], "Id");

            //;; The binding system respose changing property value
            Button button1 = new Button() { Top = 160, Left = 10, Width = 200, Text = "Set Id=99 Directly by property" };
            this.Controls.Add(button1);
            button1.Click += (s, e) =>
            {
                lst[0].Id = "99";
            };

            DataGridView dg = new DataGridView() { Top = 200, Left = 10 };
            this.Controls.Add(dg);
            dg.DataSource = lst;
        }

    }


    //;; The person class can bind any his property without any extra call fo change detection 
    public class Person
    {
        public string Id { get; set;}
        public string Name { get; set; }
    }
}

现在,TextBox在显示方面时显示Id值。但是按下“设置”按钮不会刷新DataGrid上的数据。

所以,我的问题是:

  1. 为什么在第一个示例中绑定TextBox不能正常工作?
  2. 可以说,只有在DataRow上,自动(无需进行绑定的任何额外调用)将更新从源传播到控件了吗?

2 个答案:

答案 0 :(得分:1)

由于在注释中描述此过程可能不是一个好主意,因此下面是放大版本。

  • BindingListList<T>定义为数据存储对象(我更喜欢BindinList,但是这里的IList仍然可以完成工作)。 / li>
  • 定义一个BindingSource,它将提供更改通知和货币管理。它极大地简化了WinForms中控件的绑定。

  • BindingSource.DataSource属性设置为提供数据的对象:此处为 BindingList IList >。

  • 在{strong> TextBox.Text 属性中添加Binding,该属性将绑定到数据源的属性(例如,数据表的列),并设置将Binding的{​​{3}}值设置为 BindingSource ,将 DataMember 值设置为以下属性(或列): TextBox属性绑定到的数据源。在这里,是 Id 类的Inputs属性。
  • 订阅TextBox Binding DataSource,以私密方式表示在允许更新数据源之前先验证在TextBox中输入的数据。如果输入的值不符合描述要求(例如,用户输入字母而不是数字),我们可以调用例如Parse event方法来取消数据更新
  • DataGridView.DataSource 设置为BindingSource

使用下面显示的代码会发生这种情况:

BindingSource.ResetCurrentItem


注意
我在这里使用lambda订阅 Parse 事件;如果您需要多次订阅/取消订阅此事件,则可能需要使用单独的处理程序。

internal class Inputs
{
    public int Id { get; set; }
    public string Name { get; set; }
}

internal List<Inputs> InputData = new List<Inputs>();
internal BindingSource bindingSource;

private void button1_Click(object sender, EventArgs e)
{
    bindingSource = new BindingSource();

    InputData.AddRange(new [] { 
        new Inputs() { Id = 5476, Name = "Smith" },
        new Inputs() { Id = 5477, Name = "Marlin" }
    });

    bindingSource.DataSource = InputData;

    Binding tboxBind = new Binding("Text", bindingSource, "Id", false, DataSourceUpdateMode.OnPropertyChanged);

    tboxBind.Parse += (pObj, pEvt) =>
    {
        if (!int.TryParse(pEvt.Value.ToString(), out int value))
            bindingSource.ResetCurrentItem();
    };
    textBox1.DataBindings.Add(tboxBind);
    dataGridView1.DataSource = bindingSource;
}

答案 1 :(得分:1)

为什么绑定文本框在第一个示例中无法正常工作?

这是因为TypeDescriptor的{​​{1}}没有DataRow属性。请考虑以下规则:

  • 当数据绑定到项目的属性时,该项目的类型描述符应包含具有该名称的属性。

  • 当数据绑定到列表时,列表项类型描述符应包含具有该名称的属性。

是真的吗,自动(无任何额外的do做绑定)从源到控制的传播更新仅发生在DataRow上?

不。这不是因为Id类型。这是因为DataRowINotifyPropertyChanged。请考虑以下规则:

  • 在将控件绑定到项目时,如果该项目实现了IBindingList,则UI将在更新项目后立即更新。

  • 在将数据绑定到列表控件时,如果项目实现INotifyPropertyChanged而列表实现INotifyPropertyChanged,则在更新项目或列表后立即更新UI。

更多信息

简而言之,您可以在Windows Forms Data Binding中找到详细信息。我建议阅读以下有用的文档: