WinForms网格动态过滤下,计算周工时超阈值员工占比问题
问题根源
你遇到的问题是因为DataGridView/GridView的UI过滤(比如列头筛选)不会修改BindingSource的数据源,只是在界面上隐藏不符合条件的行。而你的计算逻辑直接使用BindingSource的全量数据,导致统计时包含了被过滤掉的行,结果自然不准确。
解决方案
核心思路是:基于网格过滤后的可见数据进行统计,而不是BindingSource的原始全量数据。根据你使用的控件类型,分别采用以下实现方式:
情况1:使用原生WinForms DataGridView
直接遍历DataGridView的可见行,排除隐藏行和新行(IsNewRow),再统计符合条件的数据:
private void buttom_Calculate_Click(object sender, EventArgs e) { try { double threshold = (double)numericTextBox_Hours.GetNumericValue(); // 筛选出DataGridView中可见的、已绑定数据的行 var validVisibleRows = dataGridView1.Rows.Cast<DataGridViewRow>() .Where(row => row.Visible && !row.IsNewRow); // 统计周工时超过阈值的员工数 AboveAverageCount = validVisibleRows.Count(row => { var employeeData = row.DataBoundItem as AverageEmployeeHourModel; return employeeData != null && employeeData.WeeklyAverage.HasValue && employeeData.WeeklyAverage.Value > threshold; }); // 总行数取可见行数量 RowCount = validVisibleRows.Count(); // 计算占比 AboveAveragePercentage = RowCount > 0 ? (AboveAverageCount / RowCount) * 100 : 0; label_Percentage.Text = $"Percentage above threshold: {AboveAveragePercentage:F2}%"; } catch (Exception ex) { MessageBox.Show(ex.Message); } }
情况2:使用DevExpress GridView(从dateEdit控件判断你大概率用的是DevExpress)
利用DevExpress GridView的API直接获取过滤后的数据源,无需遍历行:
// 假设你的GridView控件名为gridView1 private void buttom_Calculate_Click(object sender, EventArgs e) { try { double threshold = (double)numericTextBox_Hours.GetNumericValue(); // 获取GridView过滤后的所有数据项 var filteredEmployeeData = gridView1.DataController.GetAllFilteredAndSortedRows() .Cast<AverageEmployeeHourModel>(); // 统计符合条件的员工数 AboveAverageCount = filteredEmployeeData.Count(item => item.WeeklyAverage.HasValue && item.WeeklyAverage.Value > threshold); // 总行数取过滤后的数量 RowCount = filteredEmployeeData.Count(); // 计算占比 AboveAveragePercentage = RowCount > 0 ? (AboveAverageCount / RowCount) * 100 : 0; label_Percentage.Text = $"Percentage above threshold: {AboveAveragePercentage:F2}%"; } catch (Exception ex) { MessageBox.Show(ex.Message); } }
补充:若使用BindingSource.Filter属性过滤
如果你是通过设置averageEmployeeHourModelBindingSource.Filter来实现过滤,可直接使用BindingSource的过滤后列表:
private void buttom_Calculate_Click(object sender, EventArgs e) { try { double threshold = (double)numericTextBox_Hours.GetNumericValue(); AboveAverageCount = averageEmployeeHourModelBindingSource.List .Cast<AverageEmployeeHourModel>() .Count(item => item.WeeklyAverage.HasValue && item.WeeklyAverage.Value > threshold); RowCount = averageEmployeeHourModelBindingSource.Count; AboveAveragePercentage = RowCount > 0 ? (AboveAverageCount / RowCount) * 100 : 0; label_Percentage.Text = $"Percentage above threshold: {AboveAveragePercentage:F2}%"; } catch (Exception ex) { MessageBox.Show(ex.Message); } }
内容的提问来源于stack exchange,提问作者William Sewell
相关产品推荐
相关产品推荐

