使用 WPF C#.NET4.5 使用 Visual Studio 2012 ulti。
旧的winforms代码:
foreach (DataGridViewRow paretoRow in ParetoGrid.Rows)
{
if ((Convert.ToInt32(paretoRow.Cells["CurrentPareto"].Value) < (Convert.ToInt32(paretoRow.Cells["NewPareto"].Value))))
{
paretoRow.Cells["pNew"].Value = downArrow
}
}
正如您所看到的,我循环浏览的每一行都会检查特定的单元格,如果为 true,则填充另一个单元格。这是我以前多次使用过的旧 winforms 代码......但是。 切换到 WPF 与我之前假设的有很大不同。
DataGrid
不包含 Row
属性。相反,我认为你需要使用:
DataGridRow paretoRow in paretogrid.Items
但我仍然不知道现在该由谁来拿到手机。
所以我的问题是,是否需要执行语法更改,如果需要,在哪里执行?或者,因为我开始相信 WPF 中的数据网格比 winforms 更能与对象一起操作,因此不需要使用名为“row”的属性,如果是这种情况,我应该知道在这个示例中使用什么逻辑/语法?
感谢你们的耐心等待,当我回家过银行假期时,我会做一些 WPF 挖掘,看看它实际上有多么不同。
人们似乎把这个复杂化了,这对我有用:
foreach (System.Data.DataRowView dr in yourDataGrid.ItemsSource)
{
MessageBox.Show(dr[0].ToString());
}
我认为您首先要做的是获取
DataGrid
的所有行:
public IEnumerable<Microsoft.Windows.Controls.DataGridRow> GetDataGridRows(Microsoft.Windows.Controls.DataGrid grid)
{
var itemsSource = grid.ItemsSource as IEnumerable;
if (null == itemsSource) yield return null;
foreach (var item in itemsSource)
{
var row = grid.ItemContainerGenerator.ContainerFromItem(item) as Microsoft.Windows.Controls.DataGridRow;
if (null != row) yield return row;
}
}
然后迭代你的网格:
var rows = GetDataGridRows(nameofyordatagrid);
foreach (DataGridRow row in rows)
{
DataRowView rowView = (DataRowView)row.Item;
foreach (DataGridColumn column in nameofyordatagrid.Columns)
{
if (column.GetCellContent(row) is TextBlock)
{
TextBlock cellContent = column.GetCellContent(row) as TextBlock;
MessageBox.Show(cellContent.Text);
}
}
是的,你说得对。 WPF
DataGrid
是围绕更好地支持对象的使用而构建的。
您可以使用类似于以下内容的 ViewModel。将它们全部构建到一个集合中,然后将该集合设置为您的
ItemsSource
。如果您想显示和图像而不是 pNew 为真/假的复选标记,您还需要使用 ValueConverter。
public class FooViewModel : INotifyPropertyChanged
{
private int currentPareto;
public int CurrentPareto
{
get
{
return currentPareto;
}
set
{
if (currentPareto == value)
return;
currentPareto = value;
OnPropertyChanged("CurrentPareto");
OnPropertyChanged("pNew");
}
}
private int newPareto;
public int NewPareto
{
get
{
return newPareto;
}
set
{
if (newPareto == value)
return;
newPareto = value;
OnPropertyChanged("NewPareto");
OnPropertyChanged("pNew");
}
}
public bool pNew
{
get
{
return CurrentPareto < NewPareto;
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
为了稍微简化一下,您可以使用基本 ViewModel 类并使用
PropertyChanged
编织。代码将简化为:
public class FooViewModel : ViewModelBase
{
public int CurrentPareto { get; set; }
public int NewPareto { get; set; }
public bool pNew { get { return CurrentPareto < NewPareto; } }
}
我什至不明白为什么在数据网格中获取行及其值如此复杂。找到方法感觉就像地狱一样。 API 甚至给出了有趣的事件名称,但这也不是那么直接切中要点。为什么人们不能只专注于基线并提供确切需要的东西,而不是各种毫无用处和意义的不同选项。我的意思是吃东西只需要勺子和叉子就可以了。自十万年前以来,从未改变过。这是我的代码,感谢提到有些人只是试图使事情变得过于复杂并浪费您时间的人。
private void dtaResultGrid_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
ActivateTestDatagridAccess();
}
public async void ActivateTestDatagridAccess()
{
try
{
await Task.Delay(500);
foreach (System.Data.DataRowView dr in dtaResultGrid.ItemsSource)
{
for (int j = 0; j < dtaResultGrid.Columns.Count; j++)
{
Console.WriteLine(dr[j].ToString());
}
Console.Write(Environment.NewLine);
}
}
catch (Exception exrr)
{
Console.WriteLine(exrr.ToString());
}
}
查尔斯的“最简单”答案为我做到了。但我用了
Items
而不是 ItemsSource
。
现在,对于遇到此错误的人:
System.InvalidCastException
Unable to cast object of type 'MS.Internal.NamedObject' to type 'System.Data.DataRowView'.
对我来说,它的作用是禁用 DataGrid 的属性
CanUserAddRows
。这将删除新行的占位符行,从而删除占位符对象(它不是 DataRowView,而是其他东西)。如果您已经禁用了此功能,那么我不知道。
因为我想循环遍历每行的每个元素,所以我添加了另一个
foreach
:
foreach (System.Data.DataRowView dr in nameofyourgrid.Items)
{
foreach (var item in dr.Row.ItemArray)
{
MessageBox.Show(item.ToString());
}
}
在 WPF 中,您可以更加动态和面向对象。您可以将“pNew”列绑定到您放入
DataGrid
中的元素的属性上,该属性将返回向下箭头。
如果值发生变化,您可以引发事件PropertyChanged
(接口INotifyPropertyChanged
),并且绑定的属性将被重新评估。
开始使用 WPF 时也很有趣的是
DataTemplate
、ControlTemplate
、Converter
。
当属性被调用时,转换器将属性值更改为 WPF 可用的值(例如 BoolToVisibility)。
DataTemplate
和 ControlTemplate
可用于更改控件的外观。
有几个很好的 WPF 教程。我还建议研究 MVVM 模式,将其用作 Businessobject 和 WPF-Control 之间的层,特别是处理您在此处尝试执行的操作。
如果您使用类的实例(如 struct_class)填充 datagridview 行 这将是使用 foreach 循环的最快方法
foreach (struct_class row in dgv.Items)
{
MessageBox.Show(row.name);
}
如果您的 DataGrid 绑定到自定义对象集合(例如
List<MyViewItem>
),则 DataGridRow 迭代显然不起作用。仅当您使用 DataTable/DataGridView 作为 DataGrid ItemsSource 时。
您可以迭代自定义 DataGrid 集合,但只有视图中的行具有评估的绑定。
为了解决这个问题,我使用了 BindingPropertyHelper 解决方案作为后备:
public static class PropertyPathHelper
{
public static object GetValue(object obj, string propertyPath)
{
Binding binding = new Binding(propertyPath);
binding.Mode = BindingMode.OneTime;
binding.Source = obj;
BindingOperations.SetBinding(_dummy, Dummy.ValueProperty, binding);
return _dummy.GetValue(Dummy.ValueProperty);
}
private static readonly Dummy _dummy = new Dummy();
private class Dummy : DependencyObject
{
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(object), typeof(Dummy), new UIPropertyMetadata(null));
}
}
以下代码将所有 DataGrid 行转换为新的(可迭代的)DataTable:
DataTable dt = new DataTable();
for (int i = 0; i < dataGrid.Columns.Count; i++)
{
var c = dataGrid.Columns[i];
if (c.Header != null)
dt.Columns.Add(new DataColumn(c.Header.ToString()));
else
dt.Columns.Add();
}
for (int rowIndex = 0; rowIndex < dataGrid.Items.Count; rowIndex++)
{
var item = dataGrid.Items[rowIndex];
var newRow = dt.NewRow();
bool written = false;
for (int columnIndex = 0; columnIndex < dataGrid.Columns.Count; columnIndex++)
{
DataGridColumn column = dataGrid.Columns[columnIndex];
FrameworkElement feColumn = column.GetCellContent(item);
if (feColumn is TextBlock tb)
{
// binding loaded (in view)
newRow[columnIndex] = tb.Text;
written = true;
}
else if (column is DataGridTextColumn textColumn
&& textColumn.Binding is Binding bind)
{
// falback and evaluate binding explicit (out of view)
object value = PropertyPathHelper.GetValue(item, bind.Path.Path);
newRow[columnIndex] = value;
written = true;
}
}
if (written == false)
{
throw new InvalidOperationException($"Could not read row index {rowIndex} of DataGrid; Source item type: {item?.GetType()?.FullName}");
}
dt.Rows.Add(newRow);
}
为什么不能直接使用这个属性来获取行数,然后使用 For 循环来迭代?
dataGridView1.Rows.Count