0

Visual Studio 2010 で作成したユーザー コントロールについて質問があります。

具体的には、デフォルトの Label .Net コントロールを拡張する単純なユーザー コントロールを作成しました。Designer を使用して、ユーザー コントロールの BackColor を「白」に指定しました (ユーザー コントロールには、他のコントロールによって占められていない独自の領域があることに注意してください)。プロジェクトをビルドした後、ツールボックスからドラッグして、同じソリューションの下にある 2 番目のプロジェクトのフォームでコントロールを使用しました。

コントロールを配置した後、ユーザー コントロールの同じプロパティを変更し、BackColor を "Red" に変更しました。ソリューション全体を再コンパイルしました (プロジェクトの依存関係をチェックして - ユーザー コントロール プロジェクトを最初に、依存する 2 番目のプロジェクトを最後に)。その後、(ツールボックスからドラッグして) フォーム上にユーザー コントロールの 2 番目のインスタンスを作成しました。この 2 番目のインスタンスは予想どおり「赤」の背景で表示されますが、最初のインスタンスは「白」の 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.vbBackColor BackColor

コントロールのデフォルトBackColorのプロパティを赤に変更すると、作成されるコントロールのすべての新しいインスタンスに影響します。これは、コントロールが引き続きデフォルトのプロパティ値を使用しているためです。ただし、そのプロパティの値を明示的にオーバーライドしたコントロールのインスタンスには影響しません。

この動作は直感的ではないように思われるかもしれませんが、実際には仕様によるものです。コントロールのすべてのインスタンスにデフォルトの背景色を継承させたい場合は、そのBackColor個々のインスタンスにプロパティを設定しないでください。

コントロールの特定のインスタンスにデフォルトの背景色を使用させるには、明示的に設定した場合でも、プロパティウィンドウでプロパティを右クリックし、[リセット]を選択します。この場合、カスタムコントロールの最初のインスタンスの背景は、その特定のプロパティのデフォルト値を継承するため、赤に変わるはずです。


更新に応じて、問題は、さまざまなコントロールクラスが独自のデフォルト値を設定することです(親クラスからそれらをオーバーライドしますControl)。カスタムコントロールの新しいデフォルトでそれらをオーバーライドする場合は、そのためのカスタムコントロールクラス内にコードを記述する必要があります。クラス全体ではなく、カスタムコントロールの特定のインスタンスにのみ影響するため、デザイナでこれを行うことはできません。

特にあなたがしなければならないことが2つあります。まず、関連するプロパティを上書きし、を使用してデフォルト値を設定します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

この一般的な規則の唯一の主な例外は、コントロールのサイズまたはパディングのデフォルトを変更する場合です。この場合、保護されたプロパティDefaultSizeDefaultPaddingプロパティをオーバーライドする必要があります。すなわち

  ''' <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フォーム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 に答える