1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

カスタムコントロールのイベントをプロパティウィンドウで非表示にしようとして躓いたこと

Last updated at Posted at 2022-03-27

はじめに

カスタムコントロールをControlを継承して作成しました。
デザイナーに対応させようとしたのですが、Controlのプロパティやイベントがプロパティウィンドウにたくさん表示されます。
無題の画像4.png

このコントロールには殆どの項目は不要なので表示したくありません。

やったこと

以下のページを参考に、プロパティを表示しないようにするのは成功しました。

  1. ControlDesignerクラスを継承したMyControlDesignerクラスを作成する
  2. PreFilterPropertiesメソッドをオーバーライドする
    1. 基底クラスControlDesignerのPreFilterProperiesを呼ぶ
    2. 引数のIDictionaryからプロパティ名をキーとしてPropertyDescriptorを取得する
    3. 2のPropertyDescriptorから、属性Browsable(false)を追加した新しいPropertyDescriptorを作成する
    4. 作成したPropertyDescriptorを、プロパティ名をキーとして引数のIDictionaryに設定する
  3. カスタムコントロールの属性としてMyControlDesignerクラスを指定する

これをイベントについても行おうとして以下のコードを作成しました。
アクションカテゴリの、ClickからMouseDoubleClickまでを非表示にしようとしています。

		protected override void PreFilterEvents(IDictionary events)
		{
			// PreFilterEventsをオーバーライドする場合は必須
			base.PreFilterEvents(events);

			// 隠したいイベントの名前を追加する
			string[] eventsToHide = {
				"Click", "DoubleClick", "MouseCaptureChanged", "MouseClick", "MouseDoubleClick",
			};

			foreach (string eventname in eventsToHide)
			{
				var ev = (EventDescriptor)events[eventname];
				if (ev != null)
				{
					AttributeCollection runtimeAttributes = ev.Attributes;

					// 元の属性数より1個多く確保して、そこに元のをコピー(後ろが1個空く)
					Attribute[] attrs = new Attribute[runtimeAttributes.Count + 1];
					runtimeAttributes.CopyTo(attrs, 0);

					// 一番後ろに属性追加
					attrs[runtimeAttributes.Count] = new BrowsableAttribute(false);

					// 新しいイベント記述子を作成して、元のイベントを置き換える
					ev = TypeDescriptor.CreateEvent(this.GetType(), eventname, ev.EventType, attrs);
					events[eventname] = ev;
				}
			}
		}

上手く動かない!

動かしてみると、非表示ではなく黒塗りになってしまいました。
無題の画像2.png

再描画させると黒塗り部分がメッセージに変わりますが、
無題の画像3.png

プロパティ表示に切り替えてイベント表示に戻そうとするとVisual Studioが落ちます。
これは困った……。

解決

よくよく見ていて、ひっかかることが。
CreateEventの第一引数のthis.GetType()。this!?

ev = TypeDescriptor.CreateEvent(this.GetType(), eventname, ev.EventType, attrs);

Microsoft Docsによると、ここはコンポーネントの型を指定するそうです。

thisってMyControlDesignerのインスタンスだよね。
EventPropertyのComponentTypeじゃないの?

- ev = TypeDescriptor.CreateEvent(this.GetType(), eventname, ev.EventType, attrs);
+ ev = TypeDescriptor.CreateEvent(ev.ComponentType, eventname, ev.EventType, attrs);

おお、上手くいきました!
ClickからMouseDoubleClickまで非表示になっています。
無題の画像.png

終わりに

調べてもあまり情報が出てこなかったので書いてみました。
読みづらかったらすみません。
改善点やツッコミ処等があればご指摘お願いします。

1
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?