看到标题大家可能会认为这个文章一定没有太大的新意,无非是忘记初始化一类的问题,但是建议大家慢慢看下去,我担保这个问题决非这么无聊,希望给大家增加一些乐趣啊!
大家可以这样重现这个问题:
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事件中。