我有一个大约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改回来为时已晚。
非常感谢。
答案 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]}" />