我有一个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一起使用吗?
使用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对象......对吗?
答案 0 :(得分:1)
多年来,我一直在努力解决DataGridView的许多问题。以下是“最佳实践”对我而言:
1a)我经常将我的数据(List)附加到SortableBindingList(那里有很多例子here,here和here。取适合你的。)< / 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;
因此只会显示您的服务器列。