来自单个DataSource的多个DataGridView

时间:2015-04-08 02:14:45

标签: c# winforms datagridview

我有一个Winform应用程序几乎可以工作,但是围绕用户通过DataGridViews更新和插入数据的方式变得越来越复杂,以及它如何在后台反馈到List中。目前,两个DataGridView都是从一个List填充的,当用户更新一个单元格时,然后从Grid更新List。我更喜欢将List用作数据源。

非常简化的数据集(服务器,功能,进程) - P.S.我无法更改我的数据集:

  

Server1,KeepAlive,SQLService
  Server1,KeepAlive,AnotherProcess
  Server1,Kill,RogueProcess
  Server2,KeepAlive,SQLService
  Server3,KeepAlive,SQLService

DataGridView1有1列包含Distinct服务器名称,DataGridView2有2列包含DataGridView1中所选服务器的所有功能和进程。用户可以编辑任何单元格,目前我会跟踪每个更改并将其反映回列表,然后刷新网格。我更喜欢使用DataGridView DataSource对象来处理它。

我的问题是:什么是最合适的数据源设置(即对象列表)?如何以不同的方式从数据源过滤到Grid的?

到目前为止,我已经尝试了以下内容。创建一个Config类:

class Config
{
    [DisplayName("Server")]
    public string server { get; set; }

    [DisplayName("Function")]
    public string function { get; set; }

    [DisplayName("Process")]
    public string checkType { get; set; }
}

创建包含这些Config对象的List:

List<Config> configurations = new List<Config>();

将列表指定为数据源:

dataGridView1.DataSource = configurations;

按预期显示所有三列数据。我怎样才能a)只显示Server列,b)只显示一个不同的列表?

我猜测DataGridView2我可以使用RowFilter只显示所选服务器:

(dataGridView2.DataSource as DataTable).DefaultView.RowFilter = ?

提前感谢您的帮助!

修改

我尝试过使用LINQ:

dataGridView1.DataSource = configs.Select(o => new { Server = o.server }).ToList();

这很有用,但我的网格是只读的,所以我也使用了自定义视图模型:

dataGridView1.DataSource = configs.Select(o => new ServerView() { Server = o.server }).ToList();

这显示了我想要的内容,但是当我编辑单元格时,更改不会反映在列表中。 LINQ可以像这样与DataSource一起使用吗?

编辑2

使用stefankmitph的例子我可以通过SortableBindingList过滤:

SortableBindingList<Config> sortableBindingList = new SortableBindingList<Config>(configs.Where(o => o.server == "Server1").ToList());
BindingSource bindingSource = new BindingSource(sortableBindingList, null);
dataGridView1.DataSource = bindingSource;

这解决了DataGridView2的问题,需要根据#1中选择的内容进行过滤。但是,我仍然无法弄清楚如何只在网格中显示某些列。 #1应该只有服务器而#2应该有剩余的两列。 LINQ查询中的select不起作用,因为我正在处理Config对象......对吗?

1 个答案:

答案 0 :(得分:1)

多年来,我一直在努力解决DataGridView的许多问题。以下是“最佳实践”对我而言:

1a)我经常将我的数据(List)附加到SortableBindingList(那里有很多例子hereherehere。取适合你的。)< / p>

假设有一个List配置;

dataGridView.DataSource = new SortableBindingList<Config>(configurations);

现在你的DataGridView是可排序的。

1b)在过滤DataSource时,有很多选项。就我而言,过滤仅适用于附加为DataSource的DataTable的BindingSource

假设有一个DataTable dataTableConfigurations:

BindingSource bindingSource = new BindingSource(dataTableConfigurations, null);
dataGridView.DataSource = bindingSource;
bindingSource.Filter = "Server = 'Server3'";

但我非常确定这不适用于作为DataSource的对象列表。

你能做什么:

SortableBindingList<Config> sortableBindingList = new SortableBindingList<Config>(configurations);
BindingSource bindingSource = new BindingSource(sortableBindingList, null);
dataGridView.DataSource = bindingSource;

通过这种方式,您可以轻松跟踪数据中的变化。 (例如,BindingSource.Current返回DataGridView的当前项)

BindingSource bindingSource = dataGridView.DataSource as BindingSource;
Config currentConfig = bindingSource.Current as Config;

如果我现在必须过滤数据,我会执行以下操作:

BindingSource bindingSource = dataGridView.DataSource as BindingSource;
List<Config> list = bindingSource.DataSource as List<Config>;
bindingSource.DataSource = list.Where(item => item.Server = 'banana').ToList();

如果您对BindingSource(TextBoxes,ComboBoxes等)有任何绑定,请记住,附加/分离DataSource会导致不必要的行为。为了避免这种情况,我暂停和恢复绑定:

bindingSource.SuspendBinding();
// do the filtering
bindingSource.ResumeBinding();

这使所有DataBindings保持活动状态。

更新:仅显示DataGridView中的某些列

这很简单。 (列名与DataSource对象中的名称相关)

var columnFunction = dataGridView.Columns["function"];
if(columnFunction != null)
    columnFunction.Visible = false;

var columnCheckType = dataGridView.Columns["checkType"];
if(columnCheckType != null)
    columnCheckType.Visible = false;

因此只会显示您的服务器列。