看到標題大家可能會認為這個文章一定沒有太大的新意,無非是忘記初始化一類的問題,但是建議大家慢慢看下去,我擔保這個問題決非這麼無聊,希望給大家增加一些樂趣啊!
大家可以這樣重現這個問題:
1,在窗體上放置一個TabControl控件有2個頁(tabPage1,tabPage2),tabPage1的為當前頁。
2,在tabPage1上放置一個 DataGridView控件dgv1,tabPage2上放置一個DataGridView控件dvg2並且兩個DataGridView的 AutoSizeColumnsMode 屬性為Fill,設置好兩個DataGridView的數據源後(這裡大家可以自己設置一些數據源,保證有一列的數據就可以,設置數組等也可以)。
3,訂閱窗體的Load事件,事件處理程序如下:
private void form1_Load(object sender, EventArgs e)
{
dgv1.Columns[0].HeaderText = "名稱";
dgv1.Columns[0].Width = 120;
dgv2.Columns[0].HeaderText = "名稱";
dgv2.Columns[0].Width = 120;//運行到這句的時候就會發生NullReferenceException異常;
}
按如上步驟,應該可以重現這個問題了,問題十分詭異,設置HeaderText時候沒有拋出NullReferenceException異常,這說明dgv2.Columns[0]不是null,經過監視窗口觀察,他的確不是null。
那到底什麼是null呢?大家可能認為我又會像過去的一些文章中用IL說明問題吧!
這回不用IL來說明,我們看看類庫中的源代碼:
DataGridViewColumn類的Width屬性是這樣定義的:
public int Width
{
get
{
return this.Thickness;
}
set
{
this.Thickness = value;
}
}
實際上也沒有做什麼,只是設置了基類DataGridViewBand的Thickness屬性,Thickness屬性定義如下:
internal int Thickness
{
get
{
if (this.bandIsRow && this.bandIndex > -1)
{
int height, minimumHeight;
GetHeightInfo(this.bandIndex, out height, out minimumHeight);
return height;
}
return this.thickness;
}
set
{
int minimumThickness = this.MinimumThickness;
if (value < minimumThickness)
{
value = minimumThickness;
}
if (value > maxBandThickness)
{
if (this.bandIsRow)
{
throw new ArgumentOutOfRangeException("Height", SR.GetString(SR.InvalidHighBoundArgumentEx, "Height", (value).ToString(CultureInfo.CurrentCulture), (maxBandThickness).ToString(CultureInfo.CurrentCulture)));
}
else
{
throw new ArgumentOutOfRangeException("Width", SR.GetString(SR.InvalidHighBoundArgumentEx, "Width", (value).ToString(CultureInfo.CurrentCulture), (maxBandThickness).ToString(CultureInfo.CurrentCulture)));
}
}
bool setThickness = true;
if (this.bandIsRow)
{
if (this.DataGridView != null && this.DataGridView.AutoSizeRowsMode != DataGridViewAutoSizeRowsMode.None)
{
this.cachedThickness = value;
setThickness = false;
}
}
else
{
DataGridViewColumn dataGridViewColumn = (DataGridViewColumn) this;
DataGridViewAutoSizeColumnMode inheritedAutoSizeMode = dataGridViewColumn.InheritedAutoSizeMode;
if (inheritedAutoSizeMode != DataGridViewAutoSizeColumnMode.Fill &&
inheritedAutoSizeMode != DataGridViewAutoSizeColumnMode.None &&
inheritedAutoSizeMode != DataGridViewAutoSizeColumnMode.NotSet)
{
this.cachedThickness = value;
setThickness = false;
}
else if (inheritedAutoSizeMode == DataGridViewAutoSizeColumnMode.Fill && this.DataGridView != null)
{
if (dataGridViewColumn.Visible)
{
IntPtr handle = this.DataGridView.Handle;
this.DataGridView.AdjustFillingColumn(dataGridViewColumn, value);
setThickness = false;
}
}
}
if (setThickness && this.thickness != value)
{
if (this.DataGridView != null)
{
this.DataGridView.OnBandThicknessChanging();
}
this.ThicknessInternal = value;
}
}
}
代碼太長了啊,我把和這個問題相關的代碼帖出來,把AutoSizeColumnsMode 屬性為Fill,會執行到這裡:
else if (inheritedAutoSizeMode == DataGridViewAutoSizeColumnMode.Fill && this.DataGridView != null)
{
if (dataGridViewColumn.Visible)
{
IntPtr handle = this.DataGridView.Handle; //我認為異常是這行代碼拋出的,這由於你的dgv2所在的TabPage並沒有激活所以這時Handle為null,所以拋出了 NullReferenceException異常
this.DataGridView.AdjustFillingColumn(dataGridViewColumn, value);
setThickness = false;
}
}
這個異常是內部拋出的!
如下方法可以解決這個問題:
1,不要把AutoSizeColumnsMode 屬性為Fill,然後再自己設置列寬。
2,可以把dgv2所在的TabPage設置為激活狀態:
private void form1_Load(object sender, EventArgs e)
{
this.tabControl1.SelectedIndex = 1;
dgv1.Columns[0].HeaderText = "名稱";
dgv1.Columns[0].Width = 120;
dgv2.Columns[0].HeaderText = "名稱";
dgv2.Columns[0].Width = 120;
}
3,在其他位置修改列寬,比如dgv2的DataBindingComplete事件中。