2012-01-06 12 views
2

興味深い問題が発生しました。 DataGridViewにDataGridViewRowを1つだけ追加すると、すべて正常に動作します。DataGridView.Rows [0]は、追加された行です。 2番目のDataGridviewRowを追加すると、実際のDataGridViewRowsはもう追加されませんが、代わりにクローンが追加されます。完全に同じように見えるが実際には同じ目的ではないクローン。2番目の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); 
+0

私にとっては、常にVB.NETを使用して「false」です。 –

+0

それは非常に奇妙です - 私は間違いなく "dgv.Rows.Add(drFirst);"コメントアウトされています。 – TomMhC

答えて

2

ItemプロパティはGridViewRowのクローンを作成し、複数の行がある場合、したがってReferenceEqualsは常にfalseでなければならない、ことを返し。

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

しかし、行が1つしかなく、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

+0

ありがとう、ティム、それだよ!この動作がデフォルトのプロパティにある可能性はありません。この背後にある理由は、datagridviewの背後にある共有行の原則と関係があります。それでも、ある行のグリッドと複数の行のグリッドとの間の動作の文書化されていない変更は、疑念の点で昼食休憩のものです。どのような場合でも、元の行を取得する方法は、 'dgv.Rows.SharedRow(index)'を呼び出すことです。 – TomMhC

0

あなたは:

DataGridViewRow drFirst = new DataGridViewRow(); 

この行のインデックス値は-1 drFirstオブジェクトに

は、ここで問題を複製コードサンプルです。 しかし、あなたが行のコレクションのようにそれを追加する場合:

DataGridViewRow drFirst = new DataGridViewRow(); 

行コレクションは、行の数に応じて、それを新たな指標を与えるには、既にコレクション内に存在します。あなたの場合、ここでインデックス= 0です。

は同様にあなたがそれを作成するときdrSecondのインデックス値は-1ですが、あなたは、コレクションを行に追加するとき、インデックス値はそれほどライン1

に変更されます。

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

を比較していますインデックス値が異なる2つのオブジェクトが異なるため、falseを返します。 このライン:

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

だけ変更し、trueを返しますされていないプロパティTagを比較しています。クラスDataGridViewRowCollection

[UPDATE]

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); 
+0

.NETがDataGridViewRowのコピー/クローンを暗黙的に作成する理由について説明します(OPの説明どおり)。 'dgv.Rows'によって返された' DataGridViewRowCollection'は配列ではなくコレクションなので、コピーを作成する必要はありません。それとは別に、私にとっては、最初の行を追加するかどうかは常に「偽」です。 –

+0

返信いただきありがとうございますが、私は既にその動作について知っていました。つまり、2番目のオブジェクトであるクローン(実際には異なるインデックス)が作成され、追加されました。私が探しているのは、なぜこれが起こり、それを止めるのかということです。 (編集:これはAzharへの返信であり、Timのコメントではありません - 遅すぎました) – TomMhC

+0

drFirstとdrSecondのメモリ割り当てが異なるので、実際には2番目のオブジェクトは最初のクローンではありません。 bool objCompare = object.ReferenceEquals(新しいDataGridViewRow()、新しいDataGridViewRow());彼らは異なるメモリ割り当てを持っているので、あなたは偽を得るでしょう。 –

関連する問題