Access to cell values of a DataGrid in WPF?

只愿长相守 提交于 2019-12-14 03:07:07

问题


We have such a scenario that we have a page including a DataGrid, and now we want to get all data from this DataGrid, but without accessing to the underlying item source of it, i.e., we want to access to the data directly from the DataGrid. It seems to be tricky but not impossible. I found many articles, like this: DataGridHelper, and this: Get WPF DataGrid row and cell, and many other ones. They are basically the same thing: to define the extension methods on DataGrid with help of another GetVisualChild function to find the target DataGridCell object. However, when I am using it, I can't find the target cell. Specifically, Each row in the DataGrid corresponds to one item from a collection of the DataContext, let's say, it is a collection of type "Employee", and each column of the DataGrid corresponds one property of class Employee, e.g, the Name, Gender, Age. Now my problem is, the above-mentioned GetCell() function always finds a DataGridCell with one Employee object as its content (the property of Content in DataGridCell), and can't go further into each property, no matter what column index I give it. For example, in the GetCell function, there is one line: Dim cell As DataGridCell = DirectCast(presenter.ItemContainerGenerator.ContainerFromIndex(column), DataGridCell), where the presenter is a DataGridCellsPresenter I got which representing the row I choose, and as soon as I give the column index, naturally I am expecting it to return the control for selected property at position I specified. But it just doesn't work as expected. Any help would be appreciated!


回答1:


The moment you use presenter.ItemContainerGenerator.ContainerFromIndex you fall into a limitation for it to work ONLY for non-virtualized items i.e. rows that are shown in the scroll view (plus some offset number of rows above and below the scroll view limits) of the datagrid.

For you to access values of all cells you will have to execute column level bindings for each row.

  1. Access the DataGrid.Items collection. This is a view of items so any items hidden by filter criteria or custom paging etc will be excluded. If you dont want that then do DataGrid.ItemsSource.Cast<object>().ToList() call.

  2. Now access all columns of the datagrid i.e. DataGrid.Columns. Assuming that they are of any type but DataGridTemplateColumn, step 3 below will extract the cell level value. For template columns you will have to specify some property value that represents the entire template of the cell. I find DataGridTemplateColumn.SortMemberPath a good candidate for this.

  3. Extract the DataGridTextColumn.Binding, DataGridCheckBoxColumn.Binding, DataGridComboBoxColumn.SelectedValueBinding or DataGridComboBoxColumn.SelectedItemBinding. Then for each item from step 1, execute the binding to extract the value.

Code

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



回答2:


I realize this is old topic, but I searched for a simple solution and finally found it. Thought others might like simple. The following example searches the datagrid by specified column for the desired value, if found will select the row.

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


来源:https://stackoverflow.com/questions/7890076/access-to-cell-values-of-a-datagrid-in-wpf

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!