为什么我不能成功地将 DataGridviewColumnCollection 绑定到 ComboBox.DataSource 并指定 Display/ValueMember?
Why can't I successfully bind a DataGridviewColumnCollection to a ComboBox.DataSource and specify a Display/ValueMember?
在尝试绑定组合以便用户可以从下拉列表中 select 列名称并从 SelectedValue 检索列索引时,我注意到组合似乎忽略了给定的 DisplayMember 和ValueMember 而不是使用 ToString()
转载:
- 在窗体上放置一个新的 DataGridView 和 ComboBox,保留它们的默认名称
- 将以下代码放在用户 Form1 的顶部:
public Form1()
{
InitializeComponent();
var dt = new DataTable();
dt.Columns.Add("A");
dt.Columns.Add("B");
dataGridView1.DataSource = dt;
comboBox1.DisplayMember = nameof(DataGridViewColumn.Name);
comboBox1.ValueMember = nameof(DataGridViewColumn.Index);
comboBox1.DataSource = dataGridView1.Columns;
}
- 运行 应用程序。您会在组合中看到两个条目,但不是
Name
"A" 和 "B" - 它看起来使用 ToString()
:
image of form - please embed
如果调换项目顺序:
comboBox1.DataSource = dataGridView1.Columns;
comboBox1.DisplayMember = nameof(DataGridViewColumn.Name);
comboBox1.ValueMember = nameof(DataGridViewColumn.Index);
C# 抱怨无法设置 DisplayMember。我更加困惑,因为:
- 设置
comboBox1.DataSource = dataGridView1.Columns;
后Display/ValueMembers都是""
- 设置
comboBox1.DisplayMember = nameof(DataGridViewColumn.Name);
后 DisplayMember 仍然是 ""
image of debugger stopped after setting displaymember - please embed
- 设置
comboBox1.ValueMember = nameof(DataGridViewColumn.Index);
后,DisplayMember 设置为 "Index"
并抛出异常
image of debugger stopped after setting valuemember - please embed
调整集合类型也不会产生任何不同的结果:
comboBox1.DataSource = dataGridView1.Columns.Cast<DataGridViewColumn>().ToList();
问题似乎与尝试绑定的 DataGridViewColumn class 有关。如果列集合被投影到具有相同属性名称的匿名类型,它可以正常工作:
comboBox1.DataSource = dataGridView1.Columns.Cast<DataGridViewColumn>().Select(c => new { c.Name, c.ColumnIndex }).ToList();
我很好奇为什么 DataGridViewColumn,显然是一个 class 和 public 命名的 props 像其他任何东西一样,在这个绑定场景中不能直接工作
这是因为这些属性不可浏览。
DataGridViewColumn
class 没有什么特别之处,即使是自定义创建的 class 行为也是一样的。这些属性(名称和索引)被标记为 [Browsable(false)]
,并且在设置数据绑定时,CurrencyManager.GetItemProperties 只是 returns 可浏览的属性。
如果您从 ValueMember, you will end up in some internal methods 开始跟踪代码,检查可浏览的属性。
最好的解决方法是您还提到的方法,将结果调整为自定义类型:
comboBox1.DataSource = dataGridView1.Columns.Cast<DataGridViewColumn>()
.Select(c => new { c.Name, c.ColumnIndex }).ToList();
comboBox1.ValueMember = "Index";
comboBox1.DisplayMember = "Name";
在尝试绑定组合以便用户可以从下拉列表中 select 列名称并从 SelectedValue 检索列索引时,我注意到组合似乎忽略了给定的 DisplayMember 和ValueMember 而不是使用 ToString()
转载:
- 在窗体上放置一个新的 DataGridView 和 ComboBox,保留它们的默认名称
- 将以下代码放在用户 Form1 的顶部:
public Form1()
{
InitializeComponent();
var dt = new DataTable();
dt.Columns.Add("A");
dt.Columns.Add("B");
dataGridView1.DataSource = dt;
comboBox1.DisplayMember = nameof(DataGridViewColumn.Name);
comboBox1.ValueMember = nameof(DataGridViewColumn.Index);
comboBox1.DataSource = dataGridView1.Columns;
}
- 运行 应用程序。您会在组合中看到两个条目,但不是
Name
"A" 和 "B" - 它看起来使用ToString()
:
image of form - please embed
如果调换项目顺序:
comboBox1.DataSource = dataGridView1.Columns;
comboBox1.DisplayMember = nameof(DataGridViewColumn.Name);
comboBox1.ValueMember = nameof(DataGridViewColumn.Index);
C# 抱怨无法设置 DisplayMember。我更加困惑,因为:
- 设置
comboBox1.DataSource = dataGridView1.Columns;
后Display/ValueMembers都是""
- 设置
comboBox1.DisplayMember = nameof(DataGridViewColumn.Name);
后 DisplayMember 仍然是""
image of debugger stopped after setting displaymember - please embed - 设置
comboBox1.ValueMember = nameof(DataGridViewColumn.Index);
后,DisplayMember 设置为"Index"
并抛出异常 image of debugger stopped after setting valuemember - please embed
调整集合类型也不会产生任何不同的结果:
comboBox1.DataSource = dataGridView1.Columns.Cast<DataGridViewColumn>().ToList();
问题似乎与尝试绑定的 DataGridViewColumn class 有关。如果列集合被投影到具有相同属性名称的匿名类型,它可以正常工作:
comboBox1.DataSource = dataGridView1.Columns.Cast<DataGridViewColumn>().Select(c => new { c.Name, c.ColumnIndex }).ToList();
我很好奇为什么 DataGridViewColumn,显然是一个 class 和 public 命名的 props 像其他任何东西一样,在这个绑定场景中不能直接工作
这是因为这些属性不可浏览。
DataGridViewColumn
class 没有什么特别之处,即使是自定义创建的 class 行为也是一样的。这些属性(名称和索引)被标记为 [Browsable(false)]
,并且在设置数据绑定时,CurrencyManager.GetItemProperties 只是 returns 可浏览的属性。
如果您从 ValueMember, you will end up in some internal methods 开始跟踪代码,检查可浏览的属性。
最好的解决方法是您还提到的方法,将结果调整为自定义类型:
comboBox1.DataSource = dataGridView1.Columns.Cast<DataGridViewColumn>()
.Select(c => new { c.Name, c.ColumnIndex }).ToList();
comboBox1.ValueMember = "Index";
comboBox1.DisplayMember = "Name";