c# - 两个年龄范围之间的列上的 Datagrid 过滤器
问题描述
我有一个数据网格视图,其中有一列类型为字符串,显示年龄范围的值,例如:
0-18
19-100
0-100
我还有一个过滤器文本框,需要过滤年龄范围
(dgv1.DataSource as DataTable).DefaultView.RowFilter =
string.Format("AgeRange LIKE '%{0}' OR AgeRange LIKE '{0}%'", textBoxFilter.Text);
问题是如果用户输入像 18 这样的数字,网格不会返回 0-100 的行
如何让数据网格返回 0-18 和 0-100?
解决方案
我认为您无法使用“LIKE”比较器执行此操作,因为您要查找的值是“数字”。要获得您正在寻找的过滤器,您将需要一个带有“>=”和“<=”的过滤器来查看目标年龄是否在该范围内。不清楚最初是如何接收数据的,如果每行中的“年龄范围”是如图所示的字符串,那么我建议几种不同的 hacky 方式。此外,尚不清楚网格中还有哪些其他列。
一种“hacky”方法是创建一个方法,该方法只返回一个新DataTable
的,其中只有落入给定目标范围内的行。为了帮助完成这项工作,第二种方法采用int
(我们正在寻找的目标值)和DataRowView
(AgeRange
我们正在比较“目标”值)。此“AgeRange”将位于行的第一列中。这里我们简单地取那个字符串范围(“0-18”)和目标值(“18”)来看看这个目标值是否在这个范围内,然后根据结果返回真或假。这可以使用string.split
拆分“AgeRange”字符串并将int.TryParse
字符串转换为数字的方法来完成。下面是一个例子。
private bool TargetIsInRange(int target, DataRowView row) {
if (row.Row.ItemArray[0] != null) {
string cellValue = row.Row.ItemArray[0].ToString();
string[] splitArray = cellValue.Split('-');
int startValue;
int endValue;
if (!int.TryParse(splitArray[0], out startValue)) {
return false;
}
if (!int.TryParse(splitArray[1], out endValue)) {
return false;
}
if (target >= startValue && target <= endValue)
return true;
}
return false;
}
当遍历网格行以确定哪些行进入新过滤器时,上述方法应该派上用场DataTable
。接下来,一个方法循环遍历网格并返回一个过滤的DataTable
. 对于网格中的每一行,我们可以调用上述方法并添加返回的行true
。
private DataTable GetFilterTable() {
DataTable filterTable = ((DataTable)dgv1.DataSource).Clone();
dgv1.DataSource = gridTable;
int targetValue = -1;
if (int.TryParse(textBox1.Text, out targetValue)) {
foreach (DataGridViewRow row in dgv1.Rows) {
DataRowView dataRow = (DataRowView)row.DataBoundItem;
if (dataRow != null) {
if (TargetIsInRange(targetValue, dataRow)) {
filterTable.Rows.Add(dataRow.Row.ItemArray[0]);
}
}
}
}
return filterTable;
}
不清楚您在哪里调用此过滤器,如果您正在过滤“字符串”,那么当用户在文本框中键入过滤器字符串时,网格将过滤用户按下的每个字符。这对字符串很好,但是,在这种情况下使用“数字”,我猜按钮会更合适。我想这是你必须决定的事情。使用Button
单击事件将所有这些放在一起以指示何时过滤网格可能如下所示
private DataTable gridTable;
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
gridTable = GetTable();
FillTable(gridTable);
dgv1.DataSource = gridTable;
textBox1.Text = "18";
}
private void FillTable(DataTable dt) {
dt.Rows.Add("0-18");
dt.Rows.Add("19-100");
dt.Rows.Add("0-100");
dt.Rows.Add("17-80");
dt.Rows.Add("18-80");
}
private DataTable GetTable() {
DataTable dt = new DataTable();
dt.Columns.Add("AgeRange", typeof(string));
return dt;
}
private void button1_Click(object sender, EventArgs e) {
if (textBox1.Text == "") {
dgv1.DataSource = gridTable;
return;
}
dgv1.DataSource = GetFilterTable();
}
哈奇方法 2
第一种方法有效;但是,我猜如果有大量数据和大量过滤,这可能会成为性能问题。因此,在这种方法中,一开始就采取了额外的步骤来利用DataTable
sRowFilter
功能,正如发布的代码所做的那样。显然,如前所述,我们不会使用“LIKE”比较器,而是使用“<=”和“>=”运算符。
为了实现这一点,我们必须以某种方式将给定的string
范围“XX-XX”变成两 (2) int
s。然后将这些整数“添加”到DataTable
. RowFilter
然后使用属性和小于和大于运算符来过滤表格将很容易。一个问题是我们需要“额外”的工作来正确设置网格的列,否则这额外的两列数据也会显示出来。
这可以在“设计器”中完成,也可以在代码中手动完成。无需过多详细说明,请记住,如果您将 aDataTable
作为数据源分配给网格并将 gridsAutoGenerateColumns
属性设置为false
... THEN 只有名称与其中一个列名DataPropertyName
“匹配”的网格列DataTable
… 将显示。在这种情况下,我们只希望显示AgeRange
带有“XX-XX”字符串的列,其他两个新列可以对用户保持隐藏。手动设置网格列可能如下所示,但是您可以在设计器中执行此操作。注意:设计器不显示AutoGenerateColumns
属性,您必须在代码中执行此操作。
private void AddGridColumn() {
DataGridViewTextBoxColumn col = new DataGridViewTextBoxColumn();
col.Name = "AgeRange";
col.DataPropertyName = "AgeRange";
col.HeaderText = "Age Range";
dgv1.Columns.Add(col);
}
重要的一点是DataPropertyName
必须匹配 中的目标列名DataTable
,否则该列将不会显示。
接下来是新的建设DataTable
。这个方法是原始的DataTable
。DataTable
使用三 (3) 列、AgeRange-string(显示)、StartRange-int 和 EndRange-int 创建一个新的。将不显示开始列和结束列。一旦构建了这个新表,foreach
就会开始循环遍历原始表中的所有行。DataTable
来自原始表格行的字符串数字被“解析”为实际数字,并与原始“范围”字符串一起添加到新的数字中。此方法可能如下所示。下面还有一个帮助方法来帮助拆分年龄范围字符串并返回一个数字。
private DataTable GetSplitTable(DataTable sourceTable) {
DataTable dt = new DataTable();
dt.Columns.Add("AgeRange", typeof(string));
dt.Columns.Add("StartRange", typeof(int));
dt.Columns.Add("EndRange", typeof(int));
foreach (DataRow row in sourceTable.Rows) {
int startValue = GetIntValue(row.ItemArray[0].ToString(), 0);
int endValue = GetIntValue(row.ItemArray[0].ToString(), 1);
dt.Rows.Add(row.ItemArray[0], startValue, endValue);
}
return dt;
}
private int GetIntValue(string rangeString, int index) {
string[] splitArray = rangeString.Split('-');
int value = 0;
int.TryParse(splitArray[index], out value);
return value;
}
将所有这些放在一起可能如下所示。请注意,按钮单击事件检查文本框是否为空,如果是,则如果应用了当前过滤器,则会删除当前过滤器。
private DataTable gridTable;
private DataTable splitTable;
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
gridTable = GetTable();
FillTable(gridTable);
splitTable = GetSplitTable(gridTable);
AddGridColumn();
dgv1.AutoGenerateColumns = false;
dgv1.DataSource = splitTable;
textBox1.Text = "18";
}
private void FillTable(DataTable dt) {
dt.Rows.Add("0-18");
dt.Rows.Add("19-100");
dt.Rows.Add("0-100");
dt.Rows.Add("17-80");
dt.Rows.Add("15-75");
}
private DataTable GetTable() {
DataTable dt = new DataTable();
dt.Columns.Add("AgeRange", typeof(string));
return dt;
}
private void AddGridColumn() {
DataGridViewTextBoxColumn col = new DataGridViewTextBoxColumn();
col.Name = "AgeRange";
col.DataPropertyName = "AgeRange";
col.HeaderText = "Age Range";
dgv1.Columns.Add(col);
}
private void button1_Click(object sender, EventArgs e) {
string filterString = "";
DataView dv;
if (textBox1.Text != "") {
filterString = string.Format("StartRange <= {0} AND EndRange >= {0}", textBox1.Text);
}
dv = new DataView(splitTable);
dv.RowFilter = filterString;
dgv1.DataSource = dv;
}
推荐阅读
- java - 如何验证显示的日期是否正确?
- vba - 复选框过滤问题
- c# - 使用身份服务器保护 API 时出现问题 - 在 Angular 中登录后无法正常工作
- docker-compose - 没有 mysql 超级用户凭据的 Fusionauth-app docker
- json - 如何在“json”处修复错误 822 意外令牌?
- apache-spark - 使用 spark-streaming 将数据发布到 kafka 主题时重复
- byte-buddy - 如何使用字节伙伴实现 ClassFileTransformer#transform?
- azure - Azure 数据同步到具有不同名称和架构的表
- r - 从 Excel 表到 R 中的数据框
- flutter - Flutter 通过支持返回上一个片段在片段之间切换