首页 > 解决方案 > 以 BindingSource 作为 DataSource 的 DataGridview 仅在选择 Row 后才显示值

问题描述

我正在使用 DataGridView 使用字符串包装类、BindingSource 和 BindingList 来显示字符串值。
但是,在启动应用程序时,这些值仅在单击行后才可见。我已经尝试查看所有可能的样式属性以查看初始黑色的来源,但没有成功。

初步外观:

在此处输入图像描述

单击(有趣的颜色以尝试了解哪种样式做了什么)或最小化和最大化窗口后:

在此处输入图像描述

表单代码(这里已经尝试了一些变种,最终版本不会是这样的):

private BindingSource dataSource;
private BindingList<StringValue> bindingList;
private List<StringValue> list = new List<StringValue>();

public MainForm()
{
    InitializeComponent();

    grdCodes.AutoGenerateColumns = false;

    bindingList = new BindingList<StringValue>(list);
    dataSource = new BindingSource(bindingList, null);
    grdCodes.DataSource = dataSource;

    // Load += MainForm_Load;
    x();
}

//private void MainForm_Load(object sender, EventArgs e)
//{
//    grdSupiCodes.AutoGenerateColumns = false;

//    bindingList = new BindingList<StringValue>(list);
//    dataSource  = new BindingSource(bindingList, null);
//    grdSupiCodes.DataSource = dataSource;
//}

private void x()
{
    list.Add(new StringValue("AAAAAAAAAAAA"));
    list.Add(new StringValue("BBBBBBBBBBBB"));
    list.Add(new StringValue("CCCCCCCCCCCC"));

    // none of the below work:
    grdCodes.ResetBindings();

    // grdCodes.Update();
    // grdCodes.Refresh();

    // grdCodes.DataSource = null;
    // grdCodes.DataSource = dataSource;
}

我的问题是,如何让应用程序启动时已经在网格中显示值?如果有帮助,我可以发布设计器代码,但没有定义黑色(表单背景为DarkGrey,在网格下可见)。

标签: c#winformsdatagridviewbindingsourcebindinglist

解决方案


鉴于描述的场景:

  1. 一个空的List<class>INotifyPropertyChanged很可能没有实现)被添加到相同类型的 BindingList 中。
  2. 空的BindingList设置为BindingSource的 DataSource 。
  3. BindingSource(绑定到仍然为空的 BindingList)设置为 DataGridView 的 DataSource

一些新项目随后被添加到列表中。
在这种情况下,很容易验证 BindingSource 没有收到任何仅订阅事件的ListChanged事件:该事件永远不会引发。

  • 即使该Bindinglist.Count属性增加到添加的项目数,此计数也仅报告 source 中包含的项目数,List<class>不会通知更改。
    DataGridView其实可以展示新的内容,但是底层的DataSource——BindingSource生成的内部List——和原来的源是断开的:当在DataGridView中选择了一个Row时,最常见的结果就是IndexOutOfRangeException引发了an,因为我们' 正在尝试从内部字典访问非同步项目-1,实际上是访问索引处的项目。

可以使用几种方法来同步内部集合:

  1. 将新项目直接添加到 BindingList 而不是源List<class>:BindingList 将在链接的 BindingSource 中生成ListChanged事件,同步集合并且List<class>无论如何都会更新源。

     bindingList.Add(new StringValue("StringValue1"));
     bindingList.Add(new StringValue("StringValue2"));
     bindingList.Add(new StringValue("StringValue3"));
    
  2. 如果List<class>由于某种原因需要在原有的Item中添加新的Item,请在添加完新的Item之后调用BindingList.ResetBinding()或方法;BindingSource.ResetBinding(false)这将生成ListChanged事件,结果将执行同步:

     list.Add(new StringValue("StringValue1"));
     list.Add(new StringValue("StringValue2"));
     list.Add(new StringValue("StringValue3"));
     bindingList.ResetBindings();
     // Or...
     // bindingSource.ResetBinding(false);
    
  3. 我们可以将 DataSource 设置为相应的 Type,而不是将BindingList<class>对象直接用作 BindingSource 的 DataSource,因此 DataGridView 将使用DataPropertyName属性 if将其 Columns 绑定到数据源AutoGenerateColumns = false,或者从源对象生成 Columns(s ) 属性名称,当AutoGenerateColumns = true

     BindingList bindingList = new BindingList<StringValue>(list);
     BindingSource bindingSource = new BindingSource(typeof(BindingList<StringValue>), null);
     dataGridView.DataSource = bindingSource;
    

    将新的 Items 添加到 sourceList<class>后,将 BindingSource 的 DataSource 设置为 BindingList,导致内部集合重新同步:

     list.Add(new StringValue("StringValue1"));
     list.Add(new StringValue("StringValue2"));
     list.Add(new StringValue("StringValue3"));
     bindingSource.DataSource = bindingList;
    

推荐阅读