WPF 迭代数据网格

问题描述 投票:0回答:9

使用 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 挖掘,看看它实际上有多么不同。

c# wpf datagrid
9个回答
32
投票

人们似乎把这个复杂化了,这对我有用:

foreach (System.Data.DataRowView dr in yourDataGrid.ItemsSource)
{
     MessageBox.Show(dr[0].ToString());
}

28
投票

我认为您首先要做的是获取

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);
      }
  } 

1
投票

是的,你说得对。 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; } }
}

1
投票

我什至不明白为什么在数据网格中获取行及其值如此复杂。找到方法感觉就像地狱一样。 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());
        }
    }

1
投票

查尔斯的“最简单”答案为我做到了。但我用了

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());
    }
}

0
投票

在 WPF 中,您可以更加动态和面向对象。您可以将“pNew”列绑定到您放入

DataGrid
中的元素的属性上,该属性将返回向下箭头。 如果值发生变化,您可以引发事件
PropertyChanged
(接口
INotifyPropertyChanged
),并且绑定的属性将被重新评估。

开始使用 WPF 时也很有趣的是

DataTemplate
ControlTemplate
Converter
。 当属性被调用时,转换器将属性值更改为 WPF 可用的值(例如 BoolToVisibility)。
DataTemplate
ControlTemplate
可用于更改控件的外观。

有几个很好的 WPF 教程。我还建议研究 MVVM 模式,将其用作 Businessobject 和 WPF-Control 之间的层,特别是处理您在此处尝试执行的操作。


0
投票

如果您使用类的实例(如 struct_class)填充 datagridview 行 这将是使用 foreach 循环的最快方法

foreach (struct_class row in dgv.Items)
{
    MessageBox.Show(row.name);
}

0
投票

如果您的 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);
}

-4
投票

为什么不能直接使用这个属性来获取行数,然后使用 For 循环来迭代?

dataGridView1.Rows.Count
© www.soinside.com 2019 - 2024. All rights reserved.