我们有这样一个场景,我们有一个包含DataGrid的页面,现在我们想从这个DataGrid获取所有数据,但是没有访问它的底层项源,即我们想直接访问数据来自DataGrid。这似乎很棘手,但并非不可能。我找到了很多文章,例如:DataGridHelper,以及:Get WPF DataGrid row and cell和其他许多文章。它们基本相同:在DataGrid上使用另一个GetVisualChild函数定义扩展方法来查找目标DataGridCell对象。但是,当我使用它时,我找不到目标细胞。具体来说,DataGrid中的每一行对应一个DataContext集合中的一个项目,比方说,它是“Employee”类型的集合,DataGrid的每一列对应一个Employee类的一个属性,例如Name,Gender ,年龄。现在我的问题是,上面提到的GetCell()函数总是找到一个DataGridCell,其中一个Employee对象作为其内容(DataGridCell中Content的属性),无论我给出什么列索引,都无法进一步进入每个属性它。
例如,在GetCell函数中,有一行:
Dim cell As DataGridCell = DirectCast(presenter.ItemContainerGenerator.ContainerFromIndex(column), DataGridCell)
,
其中,演示者是我得到的DataGridCellsPresenter,它代表我选择的行,一旦我给出列索引,我自然希望它返回指定位置的选定属性的控件。但它只是没有按预期工作。任何帮助将不胜感激!
答案 0 :(得分:0)
当您使用presenter.ItemContainerGenerator.ContainerFromIndex
时,您将陷入限制,仅适用于非虚拟化项目,即滚动视图中显示的行(加上滚动视图限制上方和下方的一些偏移行数) )数据网格。
为了访问所有单元格的值,您必须为每一行执行列级绑定。
访问DataGrid.Items
集合。这是项目的视图,因此将排除由筛选条件或自定义分页等隐藏的任何项目。如果您不想这样做,请DataGrid.ItemsSource.Cast<object>().ToList()
致电。
现在访问数据网格的所有列,即DataGrid.Columns
。假设它们是DataGridTemplateColumn
以外的任何类型,下面的步骤3将提取单元格级别的值。对于模板列,您必须指定一些属性值,该值表示单元格的整个模板。我发现DataGridTemplateColumn.SortMemberPath
是一个很好的候选人。
摘录DataGridTextColumn.Binding
,DataGridCheckBoxColumn.Binding
,DataGridComboBoxColumn.SelectedValueBinding
或DataGridComboBoxColumn.SelectedItemBinding
。然后对于步骤1中的每个项目,执行绑定以提取值。
<强>代码强>
private void Button_Click_1(object sender, RoutedEventArgs e)
{
string gridContent = string.Empty;
foreach(var item in MyDataGrid.Items)
{
foreach (var column in MyDataGrid.Columns)
{
var textCol = column as DataGridTextColumn;
var checkCol = column as DataGridCheckBoxColumn;
var comboCol = column as DataGridComboBoxColumn;
var templateCol = column as DataGridTemplateColumn;
if (textCol != null)
{
var propertyName = ((Binding)textCol.Binding).Path.Path;
var value
= item.GetType().GetProperty(
propertyName).GetValue(
item,
new object[] {});
if (((Binding)textCol.Binding).Converter != null)
{
value
= ((Binding)checkCol.Binding).Converter.Convert(
value,
typeof(object),
((Binding)checkCol.Binding).ConverterParameter,
((Binding)checkCol.Binding).ConverterCulture);
}
gridContent = gridContent + "\t" + value.ToString();
}
if (checkCol != null)
{
var propertyName = ((Binding)checkCol.Binding).Path.Path;
object value
= item.GetType().GetProperty(
propertyName).GetValue(
item,
new object[] { });
if (((Binding)checkCol.Binding).Converter != null)
{
value
= ((Binding)checkCol.Binding).Converter.Convert(
value,
typeof(object),
((Binding)checkCol.Binding).ConverterParameter,
((Binding)checkCol.Binding).ConverterCulture);
}
gridContent = gridContent + "\t" + value.ToString();
}
if (comboCol != null)
{
var propertyName = string.Empty;
if (comboCol.SelectedValueBinding != null)
{
propertyName
= ((Binding)comboCol.SelectedValueBinding).Path.Path;
}
else if (!string.IsNullOrEmpty(comboCol.SelectedValuePath))
{
propertyName = comboCol.SelectedValuePath;
}
else if (!string.IsNullOrEmpty(comboCol.DisplayMemberPath))
{
propertyName = comboCol.DisplayMemberPath;
}
var value = item.GetType().GetProperty(
propertyName).GetValue(
item,
new object[] { });
if (comboCol.SelectedValueBinding != null
&& ((Binding)comboCol.SelectedValueBinding).Converter != null)
{
var bnd = (Binding)comboCol.SelectedValueBinding;
value
= bnd.Converter.Convert(
value,
typeof(object),
bnd.ConverterParameter,
bnd.ConverterCulture);
}
gridContent = gridContent + "\t" + value.ToString();
}
if (templateCol != null)
{
var propertyName = templateCol.SortMemberPath;
var value
= item.GetType().GetProperty(
propertyName).GetValue(
item,
new object[] { });
gridContent = gridContent + "\t" + value.ToString();
}
}
gridContent = gridContent + "\n";
}
MessageBox.Show(gridContent);
}
}
答案 1 :(得分:0)
我意识到这是一个古老的主题,但我搜索了一个简单的解决方案,并最终找到了它。认为其他人可能会喜欢简单以下示例按指定列搜索数据网格以获取所需值,如果找到则将选择该行。
private void dgSetRow(DataGrid dg, string sColHeader, int iFindValue)
{
foreach (DataRowView drv in dg.Items )
{
// compare value in datarow of view
if (iFindValue == (int)drv.Row[sColHeader])
{
// select item
dg.SelectedItem = drv;
dg.ScrollIntoView(drv);
}
}
}