【问题标题】:User Control error message displayed during Compile编译期间显示的用户控制错误消息
【发布时间】:2019-12-04 18:52:22
【问题描述】:

我在 Visual Studio 2019 中创建了一个 C# 用户控件。它有一个名为“BoundLayout”的属性。

    public Layout BoundLayout
    {
        get
        {
            return _Layout;
        }

        set
        {
            _Layout = value as Layout;
            if (_Layout == null)
            {
                MessageBox.Show("Value submitted is not of type 'LAYOUT'","Invalid Value",MessageBoxButtons.OK,MessageBoxIcon.Error);
            }
            else
            {
                InitializeControl();
            }
        }
    }

如果程序尝试为属性分配不兼容的值,则会在 MessageBox 中显示错误消息。这可以正常工作。

非常奇怪的是,当我构建(而不是运行)项目时,此错误消息会显示在其模态 MessageBox 中,在您返回 Visual Studio 之前必须确认该消息。在调试和发布模式下构建时会发生这种情况。添加到属性集代码的断点不会被触发。构建成功完成,没有错误或警告,我可以运行应用程序。

应用程序(包括此用户控件)按预期运行。我以前从未遇到过这种行为。还有其他人吗?

用户控件的完整(仍在开发中)代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Dispatcher
{
    public partial class DivisionModuleGrid : UserControl
    {
        private Layout _Layout = null;

        private ObservableListSource<LayoutDivision> _LayoutDivisions;

        private DivisionModulesList _activeDivision = null;

        private int _divisionCount;

        public Layout BoundLayout
        {
            get
            {
                return _Layout;
            }

            set
            {
                _Layout = value as Layout;
                if (_Layout == null)
                {
                    MessageBox.Show("Value submitted is not of type 'LAYOUT'","Invalid Value",MessageBoxButtons.OK,MessageBoxIcon.Error);
                }
                else
                {
                    InitializeControl();
                }
            }
        }

        public DivisionModulesList ActiveDivision
        {
            get
            {
                return _activeDivision;
            }

            set
            {
                _activeDivision = value as DivisionModulesList;

                if (_activeDivision != null)
                {
                    lbl_ActiveDivision.Text = _activeDivision.DivisionName;
                }
                else
                {
                    lbl_ActiveDivision.Text = "-No Active Division-";
                }
            }
        }


        public DivisionModuleGrid()
        {
            InitializeComponent();
        }


        private void InitializeControl()
        {
            _LayoutDivisions = _Layout.LayoutDivisions;
            _divisionCount = _LayoutDivisions.Count;

            tbx_LayoutName.Text = _Layout.LayoutName;

            //  Grid Layout divide into Rows & Columns
            int tlp_rows = _divisionCount / 3;



            TableLayoutPanel tlp = (TableLayoutPanel)(Controls.Find("tlp_DivisionGrid", false)[0]);
            DivisionModulesList dml;

            foreach (LayoutDivision ld in _LayoutDivisions)
            {
                dml = new DivisionModulesList(ld);
                dml.BoundDivision = ld;

                tlp.Controls.Add(dml);

            }


        }

        private void Tlp_DivisionGrid_Paint(object sender, PaintEventArgs e)
        {

        }
    }
}

【问题讨论】:

  • 摆脱这种情况的最佳方法是弄清楚如何优雅地处理null 值(例如,改用new Layout())。我想说 MessageBox.Show() 根本不应该在 UserControl 属性的设置器中 - 只需抛出一个异常,记录它,它就不再是你的问题了。我猜 setter 是从设计器或属性窗口触发的
  • 要添加到@ASh 的评论中,您在这里尝试做的太多了。 UserControl 在技术上是另一个 UI 控件,并且应该如此。如果可以的话,它的工作应该是显示它给出的数据。不要尝试显示错误消息。

标签: c# .net winforms user-controls windows-forms-designer


【解决方案1】:

当您为用户控件创建自己的属性,并且您在另一个地方使用此用户控件时,设计器正在为此属性生成代码,例如:

 yourControl.BoundLayout = null;

在 Designer.cs 文件中搜索;它会解决问题,直到重新生成代码。

如果设计器显示您的控件,它会运行您的代码,并在设计时(而不是构建或运行时)显示您的 MessageBox。 永远避免这种情况

 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Browsable(false)]
 public Layout BoundLayout

在您的所有属性上,如果您打算仅通过代码而不是在设计器中修改它,特别是如果 null 是无效值。

当您在另一个地方再次使用您的 UserControl 时,它不会再创建此 BoundLayout=null,但对于您的 UserControl 的现有引用,您必须手动删除此行。

【讨论】:

    【解决方案2】:

    一般建议:一般来说,您应该抛出异常而不是显示 MessageBox。但这与问题无关。

    您已将属性的初始值定义为 null。这意味着,当您将控件的实例拖放到表单上时,它也会序列化 null 赋值并生成如下代码:

    userControl1.Name = "userControl1";
    userControl1.Size = new Size( 100, 100);
    userControl1.SomeProperty = null;
    ...
    

    要解决此问题,您可以使用以下任一选项:

    • 如果值为 null,则阻止设计器序列化该值。
    • 在设计时禁用验证。
    • 始终阻止设计器序列化值。 (同样由 Holger 提出)

    示例 1 - 如果值为 null,则阻止设计器序列化该值

    您可以使用DefaultValue 属性将属性的默认值设置为空。那么当你将控件拖放到窗体上或在设计时为属性分配空值时,如果该属性的值为空,则设计器不会对其进行序列化。

    private SomeType someProperty = null;
    [DefaultValue(null)]
    public SomeType SomeProperty 
    {
        get { return someProperty; }
        set
        {
            if (value == null)
                MessageBox.Show("Why null????");
            else
                someProperty = value;
        }
    }
    

    示例 2 - 在设计时禁用验证

    您可以检查控件是否在DesignMode 中然后停止验证:

    private SomeType someProperty = null;
    public SomeType SomeProperty 
    {
        get { return someProperty; }
        set
        {
            if (value == null && !DesignMode)
                MessageBox.Show("Why null????");
            else
                someProperty = value;
        }
    }
    

    【讨论】:

    • 注意:DesignMode 属性在构造函数内部无效,它是在构造函数完成后设置的。但是通常的设计器模式是在构造函数中调用 InitializeComponent。它在事件处理程序或事件处理程序覆盖(如 OnLoad())中很有用。
    • 如果你同时应用你的东西并避免设计器生成的 null 分配,那就是。因为它没有在 InitializeComponent() 中调用。 Microsoft 应该将此 DesignMode 属性设为静态,因为根据定义,它必须对所有控件具有相同的值。但他们一一设置。
    • @Holger 你不需要同时申请。一个就够了。为了更清楚,我编辑了答案。
    • @Holger 你在构造函数中关于DesignMode 的观点是正确的,但你的信息是,设计师没有调用InitializeComponent 它只是解析该方法。看看my answer here,看看这个充满错误但设计器工作得很好的例子。
    • 我已经确认了,你是对的。我没有说任何矛盾的话。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-25
    • 1970-01-01
    相关资源
    最近更新 更多