C#winform数据绑定

1.DataBindings

 控件基类(Control),有一个DataBindings对象,它是一个ControlBindingCollection类,这个类继承与BindingsCollection,里面有一个Binding的列表对象,其中Binding对象是一个记录了属性名,数据源,数据成员等的对象。


 建立一个People类,用于数据绑定:

public class People
{
    public string Name { get; set; }
    public int Age { get; set; }
}

 建立winform窗体程序,放入两个TextBox控件:

public partial class Form1 : Form
{
    People _people = new People();
    public Form1()
    {
        InitializeComponent();
        _people.Name = "QQ";
        _people.Age = 3;
        this.tbName.DataBindings.Add("Text", _people, "Name");
        this.tbAge.DataBindings.Add("Text", _people, "Age");
    }
}

 this.tbName.DataBindings.Add("Text", _people, "Name")   表示将_people的Name属性的值绑定到tbName的Text属性上,每个属性只能绑定一个源。

如果控件是如上述代码那样绑定数据源的话,修改控件的值可以影响源数据的值,即修改tbName的Text值时_people的Name值也会改变,但是修改_people的Nam值时tbName的Text值并不会改变。所以就要修改People类,如下例所示:


public class People : INotifyPropertyChanged
{
    string _name;
    int _age;

    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
            OnPropertyChanged(nameof(Name));
        }
    }

    public int Age
    {
        get { return _age; }
        set
        {
            _age = value;
            OnPropertyChanged(nameof(Age));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)  //属性变更通知
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

 People继续INotifyPropertyChanged接口,并在对应属性执行set时触发属性变更事件,会将变更后的值显示到所绑定的控件上。

PS:这里用到了nameof关键字是为了不想用字符串,因为一旦改变了属性名称,若是用的是字符串它不会自己改变,控件绑定的时候也可以这样表示。nameof只能在6.0以上版本才可以使用,若是一下版本,可参考这篇博文 6.0版本以下nameof

2.Binding 

Binding:代表某对象属性值和某控件属性值之间的简单绑定。 

this.tbName.DataBindings.Add("Text", _people, "Name");  就表示Add一个Binding,除了设置这三个参数外,还可以设置其他的参数。

PropertyName要绑定到的控件属性的名称 
DataSource绑定的数据源 
DataMember要绑定到的属性或列表 
FormattingEnabled指示是否对控件属性数据应用类型转换和格式设置false:不执行格式化,即FormatString和FormatInfo无效
DataSourceUpdateMode指示将绑定控件属性的更改传播到数据源的时间

    枚举类型:

  • OnValidation  当确定修改完成后更新数据源
  • OnPropertyChanged  每当控件属性的值更改时,将更新数据源
  • Never  永远不会更新数据源并且不分析、 验证或重新格式化文本框控件中输入的值
NullValue设置控件属性为null时的替代值当绑定的值为null时替代显示的值
FormatString指示如何显示值的格式说明符要格式化的说明符,例:“X4”,将整数格式化为4位十六进制数
FormatInfo可提供自定义格式设置行为 

例:this.tbAge.DataBindings.Add(nameof(this.tbAge.Text), _people, nameof(_people.Age), true, DataSourceUpdateMode.OnPropertyChanged, "0", "X4"); 

3.BindingSource 

BindingSource:封装窗体的数据源 


我们有的时候需要建立一个自定义控件用来显示或者设置某个对象的属性值,就可以用到BindingSource: 

public partial class UserControl1 : UserControl
{
    public UserControl1()
    {
        InitializeComponent();
        this.bindingSource1.DataSource = typeof(People);
        People p = this.bindingSource1.DataSource as People;
        this.tbName.DataBindings.Add(nameof(this.tbName.Text), this.bindingSource1, nameof(p.Name));
        this.tbAge.DataBindings.Add(nameof(this.tbAge.Text), this.bindingSource1, nameof(p.Age), true, DataSourceUpdateMode.OnValidation);
        this.errorProvider1.DataSource = this.bindingSource1;
    }

    public People People
    {
        get { return this.bindingSource1.DataSource as People; }
        set
        {
            this.bindingSource1.DataSource = value;
        }
    }
}

 这里建立一个ErrorProvider,用来校验BindingSource数据的正确性,例如这里的Age,如果设置为非Int类型,就会提示信息。

BindingSource有个DataMember属性,用来设置要显示的数据成员,例如DataSet为Source时,就可以通过设置DataMember的值来指定显示的是哪个DataTable。


下面将BindingSource应用到DataGridView控件上: 

public partial class UserControl1 : UserControl
{
    public UserControl1()
    {
        InitializeComponent();
        List<People> listPeople = new List<People>
        {
            new People{ Name = "A", Age = 1 },
            new People{ Name = "B", Age = 2 },
            new People{ Name = "C", Age = 3 },
        };
        this.bindingSource1.DataSource = listPeople;
        this.dataGridView1.DataSource = this.bindingSource1;
    }

    private void btnAdd_Click(object sender, EventArgs e)
    {
        //this.bindingSource1.AddNew();
        this.bindingSource1.Add(new People { Name = "GG", Age = 34 });
    }

    private void btnUpdate_Click(object sender, EventArgs e)
    {
        People p = this.bindingSource1.Current as People;
        p.Name = "U";
    }

    private void btnDelete_Click(object sender, EventArgs e)
    {
        //this.bindingSource1.RemoveCurrent();   //移除资源当前项
        foreach (DataGridViewRow row in this.dataGridView1.SelectedRows)
        {
            this.bindingSource1.Remove(row.DataBoundItem);
        }
    }

    private void btnSort_Click(object sender, EventArgs e)
    {
        this.bindingSource1.Sort = "Name desc";
        //this.bindingSource1.RemoveSort();  //去除排序,恢复显示
    }

    private void btnSelect_Click(object sender, EventArgs e)
    {
        this.bindingSource1.Filter = "Age = '2'";
        //this.bindingSource1.RemoveFilter();  //去除筛选,恢复显示
    }
}

通过上述代码可以验证,可以通过操纵BindingSource来控制DataGridView的显示,增删查改都适用。(如果BindingSource绑定的是集合之类时,排序和筛选不能使用,必须实现IBindingListView接口,如果绑定的是DataTable就可以) 

 

posted @ 2022-04-12 22:46  Bridgebug  阅读(1877)  评论(0编辑  收藏  举报