0

我对使用 Visual Studio 2010 创建的用户控件有疑问。

具体来说,我创建了一个简单的用户控件,扩展了默认的 Label .Net 控件。使用设计器,我将用户控件的背景色指定为“白色”(请注意,我的用户控件确实有一个没有被任何其他控件占用的区域)。构建项目后,我通过将控件从工具箱中拖动到同一解决方案下的第二个项目的表单上。

放置控件后,我修改了用户控件的相同属性并将 BackColor 设置为“红色”。我重新编译了整个解决方案(检查了项目依赖项——首先是用户控制项目,最后是依赖的第二个项目)。随后,我在表单上创建了我的用户控件的第二个实例(通过从工具箱中拖动它)。尽管第二个实例按预期显示为“红色”背景,但第一个实例仍以“白色”背景色显示。

这对我来说非常不直观,我想知道为什么?当更改影响在表单上放置后未覆盖的属性时,我希望所有控件都采用对基类所做的任何更改。我设法得出的唯一结论是,它与 VS 为控件的第一个实例生成“designer.vb”代码以及之后不再重新生成它有关,即使基本用户控件已被更改和重新编译。

有任何想法吗 ?

更新:谢谢大家的回答!我想指出,设置 BackColor 属性只是说明我的观点的一个例子。在我看来,即使在设计时没有为我的自定义控件定义任何属性,VS 也会在后面的代码中生成一组标准的属性(除了开发人员定义的任何显式属性)。因此,省略属性的显式说明并不总能解决问题(在 Designer.vb 文件中设置属性的默认 VS 机制)。我相信一劳永逸地解决这个问题的唯一方法是在控件的 New 或 Load 方法中设置属性初始化代码;当需要执行大量初始化时,并不总是一个实用的解决方案!

4

3 回答 3

2

这是错误的,因为您没有告诉设计人员该属性的默认值是什么。因此,当您将自定义标签放在表单上时,设计器会在表单的 Designer.cs 文件中生成此类代码:

        this.myLabel1.AutoSize = true;
        this.myLabel1.BackColor = System.Drawing.Color.Red;         // <=== Here !
        this.myLabel1.Location = new System.Drawing.Point(19, 22);
        this.myLabel1.Name = "myLabel1";
        this.myLabel1.Size = new System.Drawing.Size(52, 13);
        this.myLabel1.TabIndex = 0;
        this.myLabel1.Text = "myLabel1";

标记的声明破坏了它。当您现在更改控件类中的默认值时,您已经放置在任何窗体上的任何控件都不会更改为该默认颜色,设计器代码将覆盖它。

您需要使用 [DefaultValue] 属性告诉设计者您的默认值。像这样:

using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;

class MyLabel : Label {
    public MyLabel() {
        this.BackColor = Color.Red;
    }
    [DefaultValue(typeof(Color), "Red")]
    public override Color BackColor {
        get { return base.BackColor; }
        set { base.BackColor = value; }
    }
}

现在设计器将忽略分配,您在控件内所做的任何更改都将生效。属性语法很笨拙,不幸的是您需要使用字符串。

于 2012-07-27T00:32:33.510 回答
1

我设法得出的唯一结论是,它与 VS 为控件的第一个实例生成“designer.vb”代码以及之后不再重新生成它有关,即使基本用户控件已被更改和重新编译。

这是正确的结论。您明确告诉设计人员将BackColor第一个控件的 设为白色,它通过将代码插入将属性*.Designer.vb设置为白色的文件来遵守。BackColor它无条件地执行此操作,以便它覆盖控件的默认 BackColor属性。

当您BackColor将控件的默认属性更改为红色时,这会影响已创建的控件的所有实例,因为它们仍在使用默认属性值。但它不会影响您已明确覆盖该属性值的控件实例。

尽管这种行为在您看来并不直观,但它实际上是设计使然。如果您希望控件的所有实例都继承默认背景颜色,则不要BackColor为它的单个实例设置属性。

要强制控件的特定实例使用默认背景颜色,即使您已明确设置它,右键单击属性窗口中的属性并选择“重置”。在这种情况下,自定义控件的第一个实例的背景应变为红色,因为它继承了该特定属性的默认值。


为了响应您的更新,问题在于各种控件类设置了它们自己的默认值(通过它们自己从它们的父类覆盖它们Control)。如果您想用自定义控件的新默认值覆盖那些,您需要为此在自定义控件类中编写代码。您不能在设计器中执行此操作,因为这只影响自定义控件的特定实例,而不影响整个类。

您需要特别做两件事。首先,覆盖相关属性并使用DefaultValueAttribute. 其次,在类的构造函数中设置属性的默认值。

下面是一个继承自默认控件的自定义控件的示例Label。我有所有标准控件的版本,基本上只是默认强制FlatStyle属性FlatStyle.System。该代码在 VB.NET 中是任意的,但如果 C# 是您的首选方言,您应该能够轻松转换它。

Imports System.Windows.Forms
Imports System.ComponentModel
Imports System.Drawing

<ToolboxItem(True)> <ToolboxBitmap(GetType(ResFinder), "LabelEx.bmp")> _
<Description("A standard Windows label control for displaying static text and images.")> _
Public Class LabelEx : Inherits Label

    ''' <summary>
    ''' Gets or sets the flat style appearance of this label control.
    ''' </summary>
    <DefaultValue(GetType(System.Windows.Forms.FlatStyle), "System")> _
    Public Shadows Property FlatStyle As FlatStyle
       'Set the default flat style to System
       Get
          Return MyBase.FlatStyle
       End Get
       Set(ByVal value As FlatStyle)
          MyBase.FlatStyle = value
       End Set
    End Property

    ''' <summary>
    ''' Initializes a new instance of the LabelEx" class with default settings.
    ''' </summary>
    Public Sub New()
       MyBase.New()

       'Set default property values
       Me.FlatStyle = FlatStyle.System
    End Sub

End Class

此一般规则的唯一主要例外是如果您想更改控件的大小或填充的默认值。在这种情况下,您应该只覆盖 protectedDefaultSizeDefaultPadding属性;IE

  ''' <summary>
  ''' Gets the default Size of a ButtonEx control.
  ''' </summary>
  Protected Overrides ReadOnly Property DefaultSize As Size
     Get
        Return New Size(88, 26)
     End Get
  End Property

  ''' <summary>
  ''' Gets the spacing, in pixels, around the image that is displayed on this button control.
  ''' </summary>
  Protected Overrides ReadOnly Property DefaultPadding As Padding
     Get
        Return New Padding(7, 0, 0, 0)
     End Get
  End Property

在这种情况下,您不应在构造函数中为公共属性设置默认值。

有关如何编写自定义控件(以及一些有用的控件!)的更多线索,您可以查看Windows Forms Aero库。

于 2012-07-26T11:33:24.767 回答
0

你是对的,背景色是在表单设计器生成的代码中定义的。

如果您确实想在仍从 Label 继承的同时禁用设置背景颜色,则可以覆盖 BackColor 属性并将其从设计器的属性选项卡中删除:

[EditorBrowsable(EditorBrowsableState.Never)]
[Browsable(false)]
public override Color BackColor
{
    get
    { 
        return Color.Blue;
    }
    set
    {
    }
}
于 2012-07-26T11:39:22.970 回答