两个年龄段之间的列上的Datagrid过滤器

时间:2019-01-24 23:40:08

标签: c# datagridview filtering

我有一个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?

2 个答案:

答案 0 :(得分:1)

我认为您不能使用“ LIKE”比较器来执行此操作,因为您要查找的值是“数字”。要获取所需的过滤器,您需要一个带有“> =”和“ <=”的过滤器,以查看目标年龄是否在此范围内。目前尚不清楚最初如何接收数据,如果每行中的“年龄范围”是如图所示的字符串,那么我建议采用几种不同的黑客方式。此外,目前尚不清楚网格中还有哪些其他列。

一种“ hacky”方法是使该方法返回仅包含属于给定目标范围的行的新DataTable。为了帮助实现这一目标,第二种方法采用了int(我们正在寻找的目标值)和DataRowViewAgeRange我们正在将“ 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();