VisualStudio でフォームにコントロールを貼れば、プロパティ・ウインドウから色々変更できる。
もしプロパティ・ウインドウが無かったら、
private void InitializeComponent()
{
(デザイナーやプロパティ・ウインドウで色々設定した内容。)
}
【色々設定した内容】の部分を手書きで直さないといけないし、全部コンパイルしないと結果が見えない。
非常に便利なんだけど、設定する方法は実は限られている。
string,intなどデータ型
SizeやFontなど組込まれているクラス
enum型
しか、使えないように見えるが、自作のクラスも使える。
ただ単純に使うと、データのところに 『(クラス名)』と表示されるだけだ。
では、どうすれば良いのか?探してみると、みかみんのプログラミング道場 に良いサンプルコードがあった。
これを使うと、追加したShadowプロパティのデータ欄に、GrayText, 1, ToBottomRight と ちゃんと表示してくれる。
しかし、Sizeクラスのメンバー(WidthやHeight)の様にSizeの子要素としてメンバーを表示したりしないから、手入力でデータを直すには、気合を入れて No-Missで、GrayText, 1, ToBottomRight を修正しないといけない。
それではやっぱり不便なので、
public class ShadowConverter : TypeConverter
を
public class ShadowConverter : ExpandableObjectConverter
に置き換えると、Shadowにツリービューの様に [+]印が付き、そのプロパティも配下の要素として表現してくれるので、色や方向を変えやすくなる。
しかし、メンバーを変えてもShadowは知らないのでフォームに貼ったコントロールをイジらないと気が付かない(反映されない)。
そこで、Showにイベントハンドラを追加し、中で何か変わったら、コールバックさせる。
1.イベントハンドラを追加。
public event EventHandler SendEvent;
2.イベントハンドラに丸投げする処理と追加。
public void Exec()
{
//親に通知する
if (SendEvent != null)
{
SendEvent.BeginInvoke(null, null, null, null);
}
}
3.Shdawの各メソッドを上書きされたらExec()を呼び出す様に大幅に改定。
public Color Color { get ; set ; }
は
public Color Color { get { return _Color; } set { _Color = value; Exec(); } }
Color _Color;
に修正、DepthやDirectionも同様に修正。
4.カスタムコントロールのコンストラクタを追加し、イベントハンドラの登録処理を追加。
public カスタムコントロールのコンストラクタ()
{
_shadow.SendEvent += new EventHandler(ChildEventReceived);
}
5.イベントハンドラに登録するメソッドを追加。
void ChildEventReceived(object sender, System.EventArgs e)
{
Invalidate();
}
6.ここで、カスタムコントロールのクラスはソースの一番最初にしてね!と後出しで要求されるので、カスタムコントロールのクラスの部分をnamespace **** の直下に移動。
ま、これでかなり使いやすい感じになった。
しかし、コードが多すぎるような気がする。コピペだらけになりそうなConverterの部分を共通化。
public partial class EverybodyConverter : ExpandableObjectConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
return true;
else
return base.CanConvertFrom(context, sourceType);
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
return true;
else
return base.CanConvertTo(context, destinationType);
}
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
string strValue = value as string;
if (strValue == null)
return base.ConvertFrom(context, culture, value);
return StringTo(strValue);
}
public virtual object StringTo(string strValue)
{
throw new Exception(“StringTo 未実装”);
}
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
{
System.Type typeMe = value.GetType();
System.Type typeValue = value.GetType();
if (typeValue.FullName != typeMe.FullName || destinationType != typeof(string))
{
return base.ConvertTo(context, culture, value, destinationType);
}
string rc = ToString(value);
return rc;
}
public virtual string ToString(Object obj)
{
throw new Exception(“ToString 未実装”);
}
}
で、string と Object を変換するToString()とStringTo()だけ実装した方がいいかもしれない。※一応動く。
public class *****Converter : EverybodyConverter
{
public override object StringTo(string strValue)
{
・・・文字をオブジェクトに変換。
}
public virtual string ToString(Object obj)
{
・・・オブジェクトから文字列を作成。
}
}