C# 仅占一列的DataGridView进度条

C# 仅占一列的DataGridView进度条,c#,winforms,datagridview,progress-bar,C#,Winforms,Datagridview,Progress Bar,我很难为我的进度条编写代码,基本上我有一个datagridview,必须由用户填写,我希望我的进度条仅在选中第2列中的复选框时增加(或者在未选中复选框时减少),到目前为止,我在void norms\u TableDataGridView\u CurrentCellDirtyStateChanged int cnt = this.norms_TableDataGridView.Rows.Count; int i = 0; string A = thi

我很难为我的进度条编写代码,基本上我有一个datagridview,必须由用户填写,我希望我的进度条仅在选中第2列中的复选框时增加(或者在未选中复选框时减少),到目前为止,我在
void norms\u TableDataGridView\u CurrentCellDirtyStateChanged

        int cnt = this.norms_TableDataGridView.Rows.Count;
        int i = 0;
        string A = this.norms_TableDataGridView.Rows[i].Cells[2].Value.ToString(); //"Approved" Cells 

        for (i = 0; i < cnt; i++)
        {
            if (A == "True")
            {
                s_Checks++;
            }
       }
       progressBar.Value = s_Checks * (progressBar.Maximum / TOTAL_CHECKBOXES);
       
int cnt=this.norms\u TableDataGridView.Rows.Count;
int i=0;
字符串A=this.norms_TableDataGridView.Rows[i].Cells[2].Value.ToString()//“核准”单元格
对于(i=0;i
这会使进度条以高于其应有的速度增加,因为对for cycle执行操作时,它会对同一选中复选框计数不止一次。任何建议都将不胜感激,因为我的新手想法显然失败了

Filipe

我对您的代码有点不确定,但通常我会通过执行以下操作来处理您的情况:

using System.Linq;

var checkedRows = norms_TableDataGridView.Rows.Cast<DataGridViewRow>()
                  .Count(r => Convert.ToBoolean(r.Cells[2].Value));
double allRows = norms_TableDataGridView.Rows.Count;
progressBar.Value = Math.Round((checkedRows / allRows) * 100,0); 
使用System.Linq;
var checkedRows=norms\u TableDataGridView.Rows.Cast()
.Count(r=>Convert.ToBoolean(r.Cells[2].Value));
double allRows=norms\u TableDataGridView.Rows.Count;
progressBar.Value=Math.Round((选中行/所有行)*100,0);

我相信有很多方法可以做到这一点。下面是管理进度条的一种可能方法,以便网格列中的“选中”复选框指示进度条的当前值

如果未选中任何复选框,则进度条将为零。如果选中所有复选框,则进度条将满。如果选中了一半复选框,则进度条将显示一半已填充

不清楚是否允许用户“添加”行。我将假设在加载网格时,行是固定的,并且用户无法将行“添加”到网格中。否则,当添加行时,代码必须“更新”进度条的最大值

当前代码的一小部分…

当前发布的代码有点奇怪,正在做很多不必要的工作。对于初学者来说,
For
循环看起来很奇怪,因为该代码是在网格
CurrentCellDirtyStateChanged
事件中执行的……因此,每次单个单元格值变脏或更改时,该事件都会触发。因此,从技术上讲,只有一(1)个单元格已更改。当只有一个复选框值可能已更改时,循环检查所有复选框值似乎很奇怪

我假设这是因为代码没有跟踪进度条的当前值。因此,每次单个复选框值更改时都需要计算该值。我相信,即使不跟踪进度条的当前值,也有一种更简单的方法可以更改进度条值。我想在选中一个复选框并在未选中时减去1

此外,当前代码“检查”值的方式也很奇怪。
for
循环前有一行

string A = this.norms_TableDataGridView.Rows[i].Cells[2].Value.ToString();
然后,在
for
循环中有一个“检查”来查看
a
是否为“真”

if (A == "True")
这很奇怪,因为
A
在循环中从不改变。如果它是
true
,那么它在循环中总是
true
。对于
false
,也是如此。因此,当
for
循环退出时,
s_检查+
将始终为零或等于
cnt

若要修复此问题,您需要在循环的每次迭代中将
A
更改为下一个复选框值。但是,即使使用此修复,代码仍会检查自上次检查以来未更改的值。 同样,可能有一种更简单的方法

另一种方法……

我假设加载网格时,所有复选框均未选中,进度条将从零开始。此外,当网格加载数据时,进度条
最大值将设置为网格中的(固定)行数

使用这种方法,当复选框从“未选中”更改为“已选中”时,代码将向进度条值“添加”1。如果“已选中”框为“未选中”,代码将从进度条值“减去”1

private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e) {
  if (e.ColumnIndex == 1) {
    dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
    if ((bool)dataGridView1.Rows[e.RowIndex].Cells[1].Value == true) {
      if (progressBar1.Value < progressBar1.Maximum) {
        progressBar1.Value++;
      }
    }
    else {
      if (progressBar1.Value > 0) {
        progressBar1.Value--;
      }
    }
  }
}
为了避免错误并保持简单,代码只需进行检查,以确保向进度条值中添加1不会超过其
最大值。此外,检查以确保减去1不会低于
最小值

因此,这种方法如下所示。一旦网格数据加载到所有复选框都未选中的位置,我们将设置进度条、最小值和最大值。类似于

private void Form2_Load(object sender, EventArgs e) {
  dataGridView1.DataSource = YourDataSource;
  progressBar1.Maximum = dataGridView1.Rows.Count;
  progressBar1.Minimum = 0;
}
我没有使用grids
CurrentCellDirtyStateChanged
事件,而是使用grids
CellContentClick
事件

使用
CellContentClick
事件的一个问题是,当它触发时,单元格值尚未更改。我们可以轻松地反转检查逻辑,但是,为了使代码保持可读状态,我将调用grids
CommittedIt
来更新网格中的更改

在这种情况下,代码会检查复选框是否选中……在本例中,复选框位于第1列

(bool)dataGridView1.Rows[e.RowIndex].Cells[1].Value == true
如果复选框从“未选中”变为“已选中”,则代码将向进度条值添加1,如果复选框从“已选中”变为“未选中”,则代码将从其值中减去1

private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e) {
  if (e.ColumnIndex == 1) {
    dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
    if ((bool)dataGridView1.Rows[e.RowIndex].Cells[1].Value == true) {
      if (progressBar1.Value < progressBar1.Maximum) {
        progressBar1.Value++;
      }
    }
    else {
      if (progressBar1.Value > 0) {
        progressBar1.Value--;
      }
    }
  }
}
private void dataGridView1\u CellContentClick(对象发送方,DataGridViewCellEventArgs e){
如果(e.ColumnIndex==1){
dataGridView1
DataGridView reportView =  new DataGridView();
DataGridViewColumn columnId = new DataGridViewColumn()
columnId.DataPropertyName = nameof(Report.Id);
DatagridViewColumn columnTitle = new DataGridViewColumn();
columnTitle.DataPropertyName = nameof(Report.Title);
DataGridViewCheckBoxColumn columnIsRead = new DataGridViewCheckBoxColumn();
columnIsRead.DataPropertyName = nameof(Report.IsRead);
// TODO: add the columns to reportView.Columns.
private IEnumerable<report> FetchReports()
{
    ...
}
private void DisplayReports()
{
    this.reportView.DataSource = this.FetchReports();
}
public BindingList<Report> DisplayedReports
{
    get => (BindingList<Report>)this.reportView.DataSource;
    set => this.reportView.DataSource = value;
}

public Report CurrentReport => (Report)this.reportView.CurrentRow?.DataBoundItem;

public IEnumerable<Report> SelectedReports => this.reportView.SelectedCells
    .Cast<DataGridViewCell>()
    .Select(cell => (Report)cell.OwningRow.DataBoundItem)
    .Distinct();
private void Form_Load(object sender, ...)
{
    // initialize the datagridview
    this.DisplayedReports = new BindingList<Report>(this.FetchReports().ToList());
}
private void ButtonOk_Clicked(object sender, ...)
{
    ICollection<Report> reports = this.DisplayedReports;
    // Todo: if desired: find out which reports are added / removed / changed
    this.ProcessEditedReports(reports);
}