添加第二个DatagridViewRow会导致克隆

本文关键字:第二个 DatagridViewRow 添加 | 更新日期: 2023-09-27 18:19:41

我遇到了一个有趣的问题。当我只向DataGridView添加一个DataGridViewRow时,一切都如预期:DataGridView。Rows[0]是添加的行。当我以某种方式添加第二个DataGridviewRow时,实际的DataGridviewRow将不再添加,而是添加克隆。看起来完全相同但实际上不是同一对象的克隆。

所以我想知道的是为什么会这样,这种行为来自哪里,如果可能的话,如何阻止添加克隆而不是实际的行。我查看了带有Reflector的DataGridViewRowCollection的代码,但没有发现任何可疑之处,但也许我遗漏了一些东西。

下面是一个复制问题的代码示例:

DataGridView dgv = new DataGridView { AllowUserToAddRows = false };
DataGridViewTextBoxColumn dgColumn = new DataGridViewTextBoxColumn();
dgv.Columns.Add(dgColumn);
DataGridViewRow drFirst = new DataGridViewRow();
dgv.Rows.Add(drFirst); // Comment this line to showcase the problem
DataGridViewRow drSecond = new DataGridViewRow();
drSecond.Tag = new object();
dgv.Rows.Add(drSecond);
// When drFirst is added this is false - when it isn't this is true (as it should always be?)
bool thisSeemsWrong = object.ReferenceEquals(dgv.Rows[dgv.Rows.Count - 1], drSecond);
// Always true
bool thisSeemsRight = object.ReferenceEquals(dgv.Rows[dgv.Rows.Count - 1].Tag, drSecond.Tag);

添加第二个DatagridViewRow会导致克隆

DataGridViewRowCollection的Item属性创建GridViewRow的克隆并返回该克隆,因此当存在多行时,ReferenceEquals应始终为false

DataGridViewRow row2 = (DataGridViewRow) dataGridViewRow.Clone();

但如果只有一行和index=0,则返回相同的引用。

if (((index == 0) && (this.items.Count() == 1))) {
      dataGridViewRow.IndexInternal = 0;
      dataGridViewRow.StateInternal = this.SharedRowState[0];
      if (((this.DataGridView != null))) {
          this.DataGridView.OnRowUnshared(dataGridViewRow);
      }
      return dataGridViewRow;
}

以下是此属性的完整来源(来自反射):

public DataGridViewRow this[int index]
{
  get
  {
    DataGridViewRow dataGridViewRow = this.SharedRow(index);
    if (dataGridViewRow.Index != -1)
    {
      return dataGridViewRow;
    }
    if ((index == 0) && (this.items.Count == 1))
    {
      dataGridViewRow.IndexInternal = 0;
      dataGridViewRow.StateInternal = this.SharedRowState(0);
      if (this.DataGridView != null)
      {
        this.DataGridView.OnRowUnshared(dataGridViewRow);
      }
      return dataGridViewRow;
    }
    DataGridViewRow row2 = (DataGridViewRow) dataGridViewRow.Clone();
    row2.IndexInternal = index;
    row2.DataGridViewInternal = dataGridViewRow.DataGridView;
    row2.StateInternal = this.SharedRowState(index);
    this.SharedList[index] = row2;
    int num = 0;
    foreach (DataGridViewCell cell in row2.Cells)
    {
      cell.DataGridViewInternal = dataGridViewRow.DataGridView;
      cell.OwningRowInternal = row2;
      cell.OwningColumnInternal = this.DataGridView.Columns[num];
      num++;
    }
    if (row2.HasHeaderCell)
    {
      row2.HeaderCell.DataGridViewInternal = dataGridViewRow.DataGridView;
      row2.HeaderCell.OwningRowInternal = row2;
    }
    if (this.DataGridView != null)
    {
      this.DataGridView.OnRowUnshared(row2);
    }
    return row2;
  }
}

也许你会在下面的文章中找到关于why的信息(从"使用共享行"开始):

http://msdn.microsoft.com/en-us/library/ha5xt0d9.aspx

当你这样做时:

 DataGridViewRow drFirst = new DataGridViewRow();

该行的索引值在drFirst对象中为-1。但当你把它添加到Row集合中时,比如:

 DataGridViewRow drFirst = new DataGridViewRow();

行集合根据集合中已存在的行数为其提供一个新索引。在您的情况下,这里的索引为0。

类似地,对于drSecond,当您创建它时,索引值为-1,但当您将它添加到行集合时,索引数值将更改为1。

所以线路:

bool thisSeemsWrong = object.ReferenceEquals(dgv.Rows[dgv.Rows.Count - 1], drSecond);

正在比较具有不同索引值的两个对象,因此它们将不同,因此返回false。但是这条线:

bool thisSeemsRight = object.ReferenceEquals(dgv.Rows[dgv.Rows.Count - 1].Tag, drSecond.Tag);

只是比较一个未更改并返回true的属性Tag。

[更新]

DataGridViewRow drFirst = new DataGridViewRow();
//dgv.Rows.Add(drFirst); //if you comment this line then the thisSeemsWrong is true that's right because it's now comparing the row you add which is drSecond with drSecond
DataGridViewRow drSecond = new DataGridViewRow();
drSecond.Tag = new object();
dgv.Rows.Add(drSecond);
// When drFirst is added this is false - when it isn't this is true (as it should always be?)
bool thisSeemsWrong = object.ReferenceEquals(dgv.Rows[dgv.Rows.Count - 1], drSecond);

DataGridViewRow drFirst = new DataGridViewRow();
dgv.Rows.Add(drFirst); // Now because you have added the first row as drFirst, look what you are comparing against in thisSeemsWrong, you are comparing Row[0] which is drFirst with drSecond which will always be false. You either have to compare Row[1] with drSecond or Row[0] with drFirst??
DataGridViewRow drSecond = new DataGridViewRow();
drSecond.Tag = new object();
dgv.Rows.Add(drSecond);
// When drFirst is added this is false - when it isn't this is true (as it should always be?)
bool thisSeemsWrong = object.ReferenceEquals(dgv.Rows[dgv.Rows.Count - 1], drSecond);