如何以编程方式隐藏WPF DataGrid行

时间:2015-01-19 19:09:56

标签: c# wpf datagrid datatable wpfdatagrid

我有一个大约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得知这是因为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();

但我有一个SQL DataBase连接到DataGrid,删除行成了一个大问题。此外,切换可见性似乎比使用DataTable更好。

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

非常感谢。

1 个答案:

答案 0 :(得分:0)

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

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]}" />