我有一个datagridview,其中有一列类型为string的列,其中显示了年龄范围的值,例如:
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?
答案 0 :(得分:1)
我认为您不能使用“ LIKE”比较器来执行此操作,因为您要查找的值是“数字”。要获取所需的过滤器,您需要一个带有“> =”和“ <=”的过滤器,以查看目标年龄是否在此范围内。目前尚不清楚最初如何接收数据,如果每行中的“年龄范围”是如图所示的字符串,那么我建议采用几种不同的黑客方式。此外,目前尚不清楚网格中还有哪些其他列。
一种“ hacky”方法是使该方法返回仅包含属于给定目标范围的行的新DataTable
。为了帮助实现这一目标,第二种方法采用了int
(我们正在寻找的目标值)和DataRowView
(AgeRange
我们正在将“ target”值进行比较) 。此“ AgeRange”将在第一行中。在这里,我们简单地获取该字符串范围(“ 0-18”)和目标值(“ 18”),以查看该目标值是否在该范围内,然后根据结果返回true或false。可以使用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
click事件将所有内容放在一起,以发出何时过滤网格的信号可能类似于
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
的{{1}}功能。显然,如前所述,我们将不使用“ LIKE”比较器,而是使用“ <=”和“> =”运算符。
为了完成此操作,我们必须以某种方式将给定的RowFilter
范围“ XX-XX”变成两(2)个string
。然后将这些整数“添加”到int
。然后,使用DataTable
属性以及小于和大于运算符可以很容易地过滤表。一个问题是,这将需要我们做额外的工作才能正确设置网格的列,否则这些额外的两列数据也将显示。
这可以在“设计器”中完成,也可以在代码中手动完成。在不赘述的情况下,请记住,如果您将RowFilter
作为数据源分配给网格,并且将网格的DataTable
属性设置为AutoGenerateColumns
,则很有用...然后仅显示名称与false
列名称之一“匹配”的DataPropertyName
的网格列。在这种情况下,我们只希望显示带有“ XX-XX”字符串的DataTable
列,其他两个新列可以对用户隐藏。手动设置网格列可能如下所示,但是您可以在设计器中进行设置。注意:设计器不会显示AgeRange
属性,您必须在代码中执行此操作。
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
,其中包含三(3)列,即AgeRange-string(显示),StartRange-int和EndRange-int。开始和结束列将不会显示。一旦构造了这个新表,就开始遍历原始表中的所有行的DataTable
循环。原始表行中的字符串数字被“解析”为实际数字,并与原始“范围”字符串一起添加到新的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;
}
答案 1 :(得分:0)
此代码:
("AgeRange LIKE '%{0}' OR AgeRange LIKE '{0}%'", textBoxFilter.Text)
是多余的,有两个AgeRange LIKE
如果您想像textBoxFilter.Text
一样搜索,可以尝试
("AgeRange LIKE '%{0}%'", textBoxFilter.Text)
或
StringBuilder rowFilter = new StringBuilder();
rowFilter.Append("AgeRange Like '%" + textBoxFilter.Text + "%'");
(dgv1.DataSource as DataTable).DefaultView.RowFilter = rowFilter.ToString();