自分仕様のコントロール
ここまででcAlgoの持つコントロールを一通り説明してきましたが、cAlgoで用意されているコントロール類はあくまで基本的なコントロールのみです。場合によってはボタンとテキスト組み合わせたようなコントロールを使いたいということもあるでしょう。
もちろんボタンとテキストそのまま並べて使うだけでもいいんですが、同じようなコントロールをあちこちで使うのであれば、あらかじめまとめて一つのコントロールとして作っておきたいですよね。そんな場合に使えるのがこれです。
CustomControlクラス
自分の好きなコントロールを作るための抽象クラスです。
public abstract class CustomControl : ControlBase
抽象クラスのため、このままでは使えません。あくまで自分のコントロールクラスを作るときのベース用です。
メソッド
protected (void) AddChild(ControlBase chile)
子コントロールを追加します。
具体例
いまいち使い方がピンとこない方もいると思いますので具体例を示します。
こんな感じのカウンターコントロールを作ってみましょう。上下ボタンで数字増減して、Countプロパティで数字を取得するだけのものです。テキストボックスとボタンの組み合わせで実現できそうなのは想像つくと思います。
このようにCustomControlクラスを継承したクラスを定義して、コンストラクタで部品となるテキストボックスとボタンを追加してあげます。そしてボタンに増減機能つけて、Countプロパティを用意するだけです。
public class MyCounter : CustomControl {
public int Count {
get { return int.Parse(_text.Text); }
}
private TextBox _text;
public MyCounter() : base() {
// --- 自分のプロパティ設定
Width = 70;
Height = 40;
// --- 部品(子コントロール)作成
_text = new TextBox {
Text = "0",
IsReadOnly = true,
Width = 40,
Height = 40,
HorizontalAlignment = HorizontalAlignment.Left
};
var up = new Button {
Text = "▲",
FontSize = 8,
Width = 30,
Height = 20,
VerticalAlignment = VerticalAlignment.Top,
HorizontalAlignment = HorizontalAlignment.Right
};
var down = new Button {
Text = "▼",
FontSize = 8,
Width = 30,
Height = 20,
VerticalAlignment = VerticalAlignment.Bottom,
HorizontalAlignment = HorizontalAlignment.Right
};
// --- ボタンの動作設定
up.Click += _=> _text.Text = (int.Parse(_text.Text) + 1).ToString();
down.Click += _ => _text.Text = (int.Parse(_text.Text) - 1).ToString();
// --- 部品配置
AddChild(_text);
AddChild(up);
AddChild(down);
}
}
これで自分用カスタムコントロール完成です。後は他のコントロールと同じように使えます。
var counter = new MyCounter {
Margin = 10
};
var button = new Button {
Text = "print log",
Height = 20,
};
button.Click += _ => Print("カウンター数値:" + counter.Count.ToString());
var panel = new WrapPanel();
panel.AddChild(counter);
panel.AddChild(button);
Chart.AddControl(panel);
ボタンを押すとカウンターの数値が増減し、print logを押すとカウンターの値が表示され、Countプロパティの値が取れてるのがわかると思います。
MyCounterはCustomControlクラスを継承しているため、ControlBaseがもつプロパティはすべて持っており、他のコントロールと同じ感覚でプロパティの設定も可能です。
子コントロールの配置には注意が必要
部品となる子コントロールの配置方法は少し注意が必要です。上記コードのように子コントロールのVerticalAlignment, HorizontalAlignmentで位置を決定するのは、パネルなどに配置するときと同じなのです。しかしパネルなどと異なり、コントロールは重なって配置されてしまうのです。
たとえば、大きさの異なる2つのボタンを両方ともLeft、TopのAlignmentを指定してAddChildするとこんな風になってしまいます。(Chart.AddControlと同じですね。)
上記サンプルでは、簡単にするためコントロール自体の大きさを指定し、別のalignmentを指定することで重なりを避けてますが、実はこの方法好ましくありません。
Width,Heightプロパティは、コントロールを使用するときに設定される可能性があり、もしWidthかHehghtが新たに設定された場合はレイアウトが崩れてしまうからです。(上記サンプルのvar counterの宣言でWidth,Heightを設定してみるとわかります。)
実際はカスタムコントロールの子コントロールとしてはStackPanelやCanvasなどのパネルを1枚だけ置き、他のコントロールはパネル上に配置するという方法が現実的となるでしょう。
だったら最初からStackPanelを継承してもいいのでは・・・?
そうです。実はStackPanelの継承クラスでもカスタムコントロールらしきものは作ることができます。
しかし、StackPanelを継承してしまうと、その自作のカスタムコントロール自体がパネルとしてふるまうことができてしまうという問題があるのです。
カスタムコントロールとしては意味のないPanelの各種プロパティにアクセスできてしまう他、AddChildして新たな子コントロールをぶち込むことすらできてしまうんです。
これはカスタムコントロールの使われ方としては好ましくないですよね。そのため、自分用のコントロールを作りたいなら素直にCustomControlクラスを継承して作成することをお勧めします。