none
TextBoxのBackColorの既定値の制御と同じ実装 RRS feed

  • 質問

  • Visual Studo 2017
    .Net Framework 4.5
    Windowsフォームアプリケーション

    いじってたら初めて知ったんですが、TextBoxのBackColorの既定値って、ReadOnly=falseだとWindowなのに、ReadOnly=trueにした途端、Controlになっていました。
    (ReadOnlyを変えたらBackColorが自動的に変わるという意味ではなく、既定値)

    つまり、ReadOnlyの状態によってBackColorの既定値が都度変化しています。

    これと同じ実装は独自コントロールでも実現できるものなのでしょうか?
    DefaultValueAttributeでは出来なそうですが。

    2017年4月11日 6:05

回答

  • 別にReadOnlyプロパティに応じでBackColorプロパティが返す値を変化させるだけでは?

    private Color DefaultBackColor => ReadOnly ? SystemColors.Window : SystemColors.Control;
    
    Color? backColor;
    public Color BackColor {
        get => backColor ?? DefaultBackColor;
        set => backColor = value;
    }
    
    internal bool ShouldSerializeBackColor() => backColor != null && backColor != DefaultBackColor;
    internal void ResetBackColor() => backColor = null;

    ReadOnlyプロパティの値に応じて決定されるDefaultBackColorプロパティ、BackColorプロパティのバッキングストアであり、未設定状態を持つbackColorフィールドを用意します。BackColorプロパティはbackColorバッキングストアが値を持っていればそれを、持っていなければDefaultBackColorを返します。デザイナがBackColorプロパティをシリアライズすべきかどうかを判定するShouldSerializeBackColor()は値が変更されているかで判断します。リセット実行時の動作をResetBackColor()メソッドで指定できます。

    この機能はShouldSerialize メソッドと Reset メソッドによる既定値の定義で説明されています。


    • 編集済み 佐祐理 2017年4月11日 8:49 Resetメソッドの追加
    • 回答の候補に設定 Tak1waMVP, Moderator 2017年4月11日 12:38
    • 回答としてマーク takiru 2017年4月12日 8:32
    2017年4月11日 6:42

すべての返信

  • 別にReadOnlyプロパティに応じでBackColorプロパティが返す値を変化させるだけでは?

    private Color DefaultBackColor => ReadOnly ? SystemColors.Window : SystemColors.Control;
    
    Color? backColor;
    public Color BackColor {
        get => backColor ?? DefaultBackColor;
        set => backColor = value;
    }
    
    internal bool ShouldSerializeBackColor() => backColor != null && backColor != DefaultBackColor;
    internal void ResetBackColor() => backColor = null;

    ReadOnlyプロパティの値に応じて決定されるDefaultBackColorプロパティ、BackColorプロパティのバッキングストアであり、未設定状態を持つbackColorフィールドを用意します。BackColorプロパティはbackColorバッキングストアが値を持っていればそれを、持っていなければDefaultBackColorを返します。デザイナがBackColorプロパティをシリアライズすべきかどうかを判定するShouldSerializeBackColor()は値が変更されているかで判断します。リセット実行時の動作をResetBackColor()メソッドで指定できます。

    この機能はShouldSerialize メソッドと Reset メソッドによる既定値の定義で説明されています。


    • 編集済み 佐祐理 2017年4月11日 8:49 Resetメソッドの追加
    • 回答の候補に設定 Tak1waMVP, Moderator 2017年4月11日 12:38
    • 回答としてマーク takiru 2017年4月12日 8:32
    2017年4月11日 6:42
  • ご回答ありがとうございます。
    教えていただいた方法で、BackColor2なるものを作ってみました。

    ReadOnlyプロパティに応じて色が切り替わることが確認できましたが、デザイナ上でBackColor2プロパティを右クリックしてリセットを選択した際、ReadOnlyプロパティの状態に応じた既定値に戻す、ということが実現できません。

    using System.ComponentModel;
    using System.Drawing;
    using System.Windows.Forms;
    
    namespace WindowsFormsApp1
    {
        public class ExTextBox : TextBox
        {
            private new Color DefaultBackColor => ReadOnly ? Color.Red : Color.Blue;
    
            Color? backColor;
    
            [Browsable(true)]
            public Color BackColor2
            {
                get => this.backColor ?? this.DefaultBackColor;
                set
                {
                    this.backColor = value;
                }
            }
    
            internal bool ShouldSerializeBackColor()
            {
                return this.backColor != null && this.backColor != this.DefaultBackColor;
            }
        }
    }
    

    2017年4月11日 8:12
  • 失礼しました。情報を分散させないために元回答にResetメソッドについてを加筆しました。ご確認ください。
    2017年4月11日 8:50
  • できました!ありがとうございます!!
    ShouldSerialize メソッドと Reset メソッドによる既定値の定義は初めて知りました。
    任意のプロパティ名を連結して、状態を管理・操作できるんですね。

    いろいろいじってみた結果、上記ページにも書いてありますが、以下のことが確認できました。
     ・プロパティ値が変更されていない時に、プロパティ値が太字にならない。(ShouldSerializeXXX()の役割)
     ・既定値のリセットが行える。(ResetXXX()の役割)

    実行時にボタン起因などでReadOnlyプロパティが変更された時に、リアルタイムに背景色が変わらなかったので(フォーカスがあたると色が変わった)、プロパティのGetterでRefresh()することで解決しました。

    using System.ComponentModel;
    using System.Drawing;
    using System.Windows.Forms;
    
    namespace WindowsFormsApp1
    {
        class ExTextBox : TextBox
        {
            private Color DefaultBackColor2 => ReadOnly ? Color.Red : Color.Blue;
    
            Color? backColor2;
    
            [Browsable(true)]
            public Color BackColor2
            {
                get
                {
                    this.Refresh();
                    this.backColor2 ?? this.DefaultBackColor2;
                }
                set =>this.backColor2 = value;
            }
    
            internal bool ShouldSerializeBackColor2() => this.backColor2 != null && this.backColor2 != this.DefaultBackColor2;
    
            internal void ResetBackColor2() => this.backColor2 = null;
        }
    }



    • 編集済み takiru 2017年4月11日 10:13
    2017年4月11日 9:44
  • ReadOnlyChangedイベントとBackColorChangedイベントがあるのでこれらを使って

    protected override void OnReadOnlyChanged(EventArgs e) {
        base.OnReadOnlyChanged(e);
        OnBackColorChanged(e);
    }

    としてみるのはどうでしょうか?

    2017年4月11日 13:19