【问题标题】:How would I set the label of my UserControl at design time?如何在设计时设置我的 UserControl 的标签?
【发布时间】:2011-11-08 15:13:50
【问题描述】:

设置如下:我创建了一个用户控件 MyUserControl。在这个控件上有一个简单的标签。当我在窗体上放置此控件的新实例时,我希望标签是控件的名称。例如,如果这是控件的第一个实例,VStudio 会自动将其名称设置为“myUserControl1”。我只想将标签读取为“myUserControl1”。如果这是第五个控件,VStudio 会将其命名为 myUserControl5。我希望标签相应地改变......但前提是它尚未设置。一旦我将它设置为“标签”,它就应该被单独放置。

我认为这很容易。在构造函数中,设置 label1.Text = this.Name。但后来我意识到,在实例化时 this.Name 只是 MyUserControl。它还没有被 VisualStudio 和 CONTAINING InitializeComponent() 方法命名。

啊!我将覆盖“名称”字段。设置好后,检查 DesignMode 并更新标签!...但我无法覆盖名称。它不是虚拟的或抽象的。我可以使用“new”来强制它,但是它永远不会触发,从而破坏了目的。

当设计者为控件命名时,我可以使用哪个事件来表示?我知道当他们在表单上放置控件时,redmond 的人总是这样做,所以这是很有可能的。我其实被这个小谜语难住了。

【问题讨论】:

  • 有趣的挑战。在您删除或剪切/粘贴任何用户控件之前,我只提出了几种可以正常工作的方法。 Name 属性似乎在设计时实际上并没有改变。现在必须做一些真正的工作......祝你好运!
  • 这需要自定义设计器。 ControlDesigner.InitializeNewComponent() 就是一个很好的例子。问题是,UserControl 的设计器不是公开的,因此无法派生。

标签: c# winforms


【解决方案1】:

如何重写调用Load 事件的OnLoad 方法?

如果这不起作用,那就有点草率了,但是您可以使用 TextChanged 事件或 SizeChanged 事件,因为它们都是在设计师设置 Name 属性之后调用的(它设置值按字母顺序排列)。

【讨论】:

  • 它仍然将名称保留为“MyUserControl”而不是 myUserControl5。
  • 两个?嗯......我唯一的其他建议是设置一个计时器以等待继续检查更改(然后在有更改时停止它)。
  • 没有。我确信 TextChanged 或 SizeChanged 事件会起作用,但是——正如你所指出的——它非常草率。我知道必须有一个非常简单的方法来做到这一点。为这么简单的事情引入草率的代码势必会导致其他错误。
  • 这是非常正确的,如果我在你的鞋子里,我会寻找另一种方式。但是,如果遇到它并且我找不到更好的方法,我会实施它并对其进行大量评论,解释它的作用以供将来参考..
  • 也许你应该重新考虑一下推理?也许这个名字不适合这份工作。通常设计者将UserControl 的Text 属性设置为这个名称,你可以直接使用吗?
【解决方案2】:

所以,这是最终的答案:

根据 Hans 的建议,它确实需要一个 ControlDesigner。我创建了一个简单的设计器,它可以与一些内部属性交互,并且我确实让它工作了。不过,这里有一个问题:这有点像 hack。似乎没有一个字段具有我正在寻找的值,所以我必须对一个对象执行.ToString(),然后解析出第一部分。我认为这将尽可能干净。

public class MyControlDesigner : ControlDesigner
{
    public MyControlDesigner()
    {
    }


    public override void InitializeNewComponent(IDictionary defaultValues)
    {
        base.InitializeNewComponent(defaultValues);

        MyControl control1 = this.Component as MyControl;
        control1.LabelText = control1.ToString().Split(" ".ToCharArray())[0];
    }
}

然后在 MyControl 的顶部,我简单地添加了一个新属性:

[DesignerAttribute(typeof(MyControlDesigner))]
public partial class MyControl : UserControl
{
    ...

    // Using the property "Text" Causes Visual Studio to crash!!!
    public string LabelText
    {
        get { return label1.Text; }
        set { label1.Text = value; }
    }

    ...
}

如您所见,它不是很复杂,但有点 hack-ish。当我试图覆盖“文本”时,控件锁定了 IDE。不知道为什么,但是当我称它为“LabelText”时,它工作得很好。

【讨论】:

  • UserControl 已经有一个 Text 属性,因此您必须将其更改为“public new string Text {...”才能使用它。
【解决方案3】:

编辑设计器文件。例如,假设我有一个名为 Form1 的表单。所以,我会在 Visual Studio 中有 Form1.cs、Form1.resx 和 Form1.Designer.cs。如果打开 Form1.Designer.cs 你会看到:

   #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>

这是一个警告,但您仍然可以编辑此文件。

这是一个示例编辑,我将 label3 文本设置为 label1 的名称:

            // 
            // label3
            // 
            this.label3.AutoSize = true;
            this.label3.Location = new System.Drawing.Point(371, 146);
            this.label3.Name = "label3";
            this.label3.Size = new System.Drawing.Size(35, 13);
            this.label3.TabIndex = 10;
            this.label3.Text = "label3";
            //My Edit
            this.label3.Text = this.label1.Name;

现在在 Visual Studio 的表单设计器中,我看到 label3 有 label1 的名称:

类似的方法可用于您的用户控制。

【讨论】:

  • 设计者可以随时重新生成此代码,并在每次刷新时将其放回常量字符串。另外,此时您不能保证 label1.Name 已设置。
  • 好点子,一定要发表评论或提醒大家这一点,因为更改可能会在不经意间被吹走。任何自动生成的代码都有这个问题,因此代码文件顶部的警告。只要自定义代码在设置了label1.name之后就可以了。有必要查看设计器代码以确保自定义代码位于正确的位置。并不是说这是最好的,但可能是一个可行的解决方法。除了编辑模板之外,我认为无法直接访问自动生成的设计器文件。
  • 确实如此。虽然没有完美的解决方案。通常,如果没有简单的方法来做到这一点,则意味着微软不希望你这样做。不过,我看不出他们对此的推理。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-15
  • 1970-01-01
  • 2021-07-08
  • 2012-11-04
相关资源
最近更新 更多