いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

Enabledをfalseにしても背景色と前景色が変わらないテキストボックス (ForeColor, BackColor, OnPaint, OnEnabledChanged, Frameコントロール)

VB6には、Frameコントロールというのがあり、そのコントロール(てかコンテナ)に
コントロールを載せたりします。windows formsではGroupBoxと同じ使い方を
したりします。


で、このFrameコントロールですが、こいつのEnabledをfalseにするとFrameコントロール自身は
グレーになるのですが内部に乗っている各コントロールは入力が出来ない状態なのに前景色と背景色が
変わりません。つまり、背景がグレーになったりしないのです。


これと同じ事をwindows formsでやろうとするとちょっと大変です。
なぜなら、GroupBox, Panelなどのコンテナ系のコントロールのEnabledをfalseにすると
下位のコントロールもfalseになります。その際に、下位のコントロールはちゃんとdisable状態
(つまり背景がグレーになり、文字色も変わります。)になります。(こっちが本来のあるべき動作だと
思いますが・・)


んで、やろうとすると以下の方法などになります。

  1. カスタムコントロールを作成
  2. PanelなどでEnabled=falseとするのではなく、各コントロールを一つ一つReadOnlyにしていく


今回は、カスタムコントロールの方向でやってみます。
このサンプルを作成するのに、いろいろリソースを参照しましたが、URLを失念しました。すみません・・。


とりあえず、以下サンプルです。

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

namespace CustomControls {
    public partial class CustomEnabledStateTextBox : TextBox {

        public CustomEnabledStateTextBox() {
            InitializeComponent();
        }

        protected override void OnEnabledChanged(EventArgs e) {
            //
            // Enabledの値から、自前で描画するのかシステムにまかせるのかを決定.
            //
            this.SetStyle(ControlStyles.UserPaint, !this.Enabled);
            this.Invalidate();
            base.OnEnabledChanged(e);
        }

        protected override void OnPaint(PaintEventArgs e) {
            //
            // 基底の描画処理をまず行う。
            //
            base.OnPaint(e);

            //
            // 文字の描画は、自前で行う。
            //
            using(StringFormat sf = new StringFormat()) {
                if(this.TextAlign == HorizontalAlignment.Center) {
                    sf.Alignment = StringAlignment.Center;
                } else if(this.TextAlign == HorizontalAlignment.Left) {
                    sf.Alignment = StringAlignment.Near;
                } else {
                    sf.Alignment = StringAlignment.Far;
                }

                using(SolidBrush brush = new SolidBrush(ForeColor)) {
                    e.Graphics.DrawString(
                        base.Text, base.Font, brush, new Rectangle(-1, 2, base.Width, base.Height), sf);
                }

                if(this.BorderStyle == BorderStyle.FixedSingle) {
                    e.Graphics.DrawRectangle(new Pen(Color.Black), 0, 0, this.Width - 1, this.Height - 1);
                }
            }
        }
    }
}


ちなみに、Enabled=falseにするのではなく、ReadOnlyプロパティを操作していくやり方では

//
// 配下のテキストボックスの状態を一気に変更する
//
foreach(Control c in Controls){
    if(c is TextBoxBase){
        TextBoxBase t = c as TextBoxBase;
        
        t.ReadOnly  = true;
        t.TabStop   = false;
        t.BackColor = SystemColors.Window;
    }
}


としても同じ状態になるはずです。