【问题标题】:How to hide WPF DataGrid rows programmatically如何以编程方式隐藏 WPF DataGrid 行
【发布时间】:2015-01-19 19:09:56
【问题描述】:

我有一个大约 2500 个条目的 DataGrid。我希望用户能够进行搜索,并且对于不包含搜索词的行进行隐藏。

这是我的伪代码策略,我是 C#、.Net 和 WPF 的新手,因此请随意推荐替代方法。

for each Row in DataGrid
    for each Column in Row
        if Cell doesn't contains SearchQuery
            hide Row
            break

在 C# 中:

        List<int> rowsWithoutMatch = new List<int>();

        for (int i = 0; i < dataGrid.Items.Count; i++)
        {
            DataGridRow row = (DataGridRow)dataGrid.
                              ItemContainerGenerator.ContainerFromIndex(i);

            if (row != null)
            {
                for (int j = 0; j < dataGrid.Columns.Count; j++)
                {
                    DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>(row);

                    if (presenter != null)
                    {
                        DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(j);

                        if (cell != null)
                        {
                            TextBlock tb = cell.Content as TextBlock;
                            string content = tb.Text;

                            if (!(content).Contains(columnFilters[j]))
                            {
                                row.Visibility = Visibility.Collapsed;
                                break;
                            }
                        }
                    }
                }
            }
        }

我遇到了这个奇怪的错误,row != null 仅在前 24 次迭代中,之后它全部为空,因此它停止遍历行。

我从this SO question 中了解到,这是因为 DataGrid 中只有 24 行可见,并且不在屏幕上的行都是空的。

我通过将标签VirtualizingStackPanel.IsVirtualizing="False" 放入DataGrid XMAL 解决了这个问题,但现在它一次加载所有行并且速度非常慢。与添加dataGrid.UpdateLayout(); dataGrid.ScrollIntoView(dataGrid.Items[i]); 相同,但也有更多错误。

我也试过这个,速度更快

        dataGrid.DataContext = dt.AsDataView();

        for (int i = dt.Rows.Count - 1; i >= 0; i--)
        {
            DataRow dr = dt.Rows[i];

            for (int j = 0; j < columnFilters.Length; j++)
            {
                if (! dr[j].ToString().Contains( columnFilters[j] ))
                {
                    dr.Delete();
                    break ;
                }
            }
        }

        dataGrid.DataContext = dt.AsDataView();

但是我有一个连接到 DataGrid 的 SQL 数据库,删除行成为一个大问题。另外,切换可见性似乎比乱用 DataTable 更好。

我怎样才能让它更快?甚至,什么是完全不同/更好的方法来做我想做的事情?对于这类事情,windows 窗体似乎有更多选择,但从 WPF 改回来为时已晚。

非常感谢。

【问题讨论】:

  • 只需绑定到 LINQ 查询输出
  • @Blam 你能说得更详细些吗?我是 C# 新手,不熟悉 LINQ
  • 您不应循环显示列表。您的 SQL 查询应该在您的模型中填充一个 DataTable,并且您的视图应该在该表上有 DataView,只显示您需要的字段和您需要的行
  • 这应该让你开始msdn.microsoft.com/en-us/library/bb546190(v=vs.110).aspx我也有collectionviewsource

标签: c# wpf datagrid datatable wpfdatagrid


【解决方案1】:

这里是一个简单的、非优化的 DataTable to Object,可以简单地在 Linq 上查询

public class LinqTable
{

    public LinqTable()
    {

    }

    public LinqTable(DataTable sourceTable)
    {
        LoadFromTable(sourceTable);
    }

    public List<LinqRow> Rows = new List<LinqRow>();

    public List<string> Columns
    {
        get
        {
            var columns = new List<string>();

            if (Rows != null && Rows.Count > 0)
            {                    
                Rows[0].Fields.ForEach(field => columns.Add(field.Name));
            }

            return columns;
        }
    }

    public void LoadFromTable(DataTable sourceTable)
    {
        sourceTable.Rows.Cast<DataRow>().ToList().ForEach(row => Rows.Add(new LinqRow(row)));
    }

    public DataTable AsDataTable()
    {
        var dt = new DataTable("data");

        if (Rows != null && Rows.Count > 0)
        {
            Rows[0].Fields.ForEach(field =>
                {
                    dt.Columns.Add(field.Name, field.DataType);
                });

            Rows.ForEach(row=>
                {
                    var dr = dt.NewRow();

                    row.Fields.ForEach(field => dr[field.Name] = field.Value);

                    dt.Rows.Add(dr);
                });
        }

        return dt;
    }
}

public class LinqRow 
{
    public List<LinqField> Fields = new List<LinqField>();

    public LinqRow()
    {

    }

    public LinqRow(DataRow sourceRow)
    {
        sourceRow.Table.Columns.Cast<DataColumn>().ToList().ForEach(col => Fields.Add(new LinqField(col.ColumnName, sourceRow[col], col.DataType)));
    }

    public object this[int index]
    {
        get
        {
            return Fields[index].Value;
        }
    }
    public object this[string name]
    {
        get
        {
            return Fields.Find(f => f.Name == name).Value;
        }
    }

    public DataTable AsSingleRowDataTable()
    {
        var dt = new DataTable("data");

        if (Fields != null && Fields.Count > 0)
        {
            Fields.ForEach(field =>
            {
                dt.Columns.Add(field.Name, field.DataType);
            });

            var dr = dt.NewRow();

            Fields.ForEach(field => dr[field.Name] = field.Value);

            dt.Rows.Add(dr);
        }

        return dt;
    }
}

public class LinqField
{
    public Type DataType;
    public object Value;
    public string Name;

    public LinqField(string name, object value, Type dataType)
    {
        DataType = dataType;
        Value = value;
        Name = name;
    }

    public LinqField(string name, object value)
    {
        DataType = value.GetType();
        Value = value;
        Name = name;
    }

    public override string ToString()
    {
        return Value.ToString();
    }      
}

调用非常简单且具有约束力。

// this create a lighter object for linq.
var myTable = new LinqTable(myDatatable);

// want to see only active clients
var filteredResult = myTable.Rows.Where(field => Convert.ToBoolean(field["IsActive"].ToString()) == true).ToList();

// now i want sort by name
var filteredResult = myTable.Rows.OrderBy(field => field["Name"].ToString()).ToList();

要在 XAML 中绑定,您可以使用整数或字符串索引器

// by int indexer
<Textbox Text="{Binding [2]}" />

// by string indexer
<Textbox Text="{Binding [Name]}" />

【讨论】:

  • 好的,我试试这个。我将不得不更改很多代码,因为有很多事情要做,比如用户可以添加或删除可见列,他们可以编辑数据网格,从而更新 SQL 数据库。我能用 LINQ 做这些事情吗?
  • 显示的列将受到 XAML 控件的限制。如果需要,您可以显示 2 列。您可以在每列上绑定可见性状态,并且只显示您想要的。
猜你喜欢
  • 2017-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-16
  • 1970-01-01
  • 1970-01-01
  • 2014-05-12
  • 2011-02-21
相关资源
最近更新 更多