随笔 - 139  文章 - 0  评论 - 421  阅读 - 17万

一个十分诡异的NullReferenceException异常

看到标题大家可能会认为这个文章一定没有太大的新意,无非是忘记初始化一类的问题,但是建议大家慢慢看下去,我担保这个问题决非这么无聊,希望给大家增加一些乐趣啊!
大家可以这样重现这个问题:
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事件中。
posted on   周雪峰  阅读(5518)  评论(3编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
< 2010年10月 >
26 27 28 29 30 1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31 1 2 3 4 5 6

点击右上角即可分享
微信分享提示