トップ回答者
コンポーネントを配置した瞬間を判断したい

質問
-
自作コンポーネントを作っていたら、ちょっと困った事象に出会ってしまい、どうしたもんかという状態で、
どなたか助けてください。
public partial class Component1 : TextBox { protected override void OnTextChanged(EventArgs e) { base.OnTextChanged(e); MessageBox.Show("tes5t"); } }
例えばこういったコードのコンポーネントをデザイン上で配置すると、OnTextChanged()が2度走行してしまいます。
走行する理由は、コンポーネントを配置した一瞬だけNameと同一値がTextに設定され、その後にText値が空に設定される為のようです。
デザイン時にも処理を行わせたい為、DesignModeによる条件判断は利用せず、『コンポーネントを配置したその瞬間』
だけを制御し、処理させないようにしたいです。
今のところ、NameとTextが同一値の場合のみ処理を抜けるようにしていますが、利用者が意図的に
NameとTextを同一値に設定した場合に、本来走行して欲しい制御が行われない為、どうにかできないか
悩んでいます。
どうにかする方法をご存知の方はおりますでしょうか?
回答
-
とりあえずVS2008,2010,2012では、貼り付けたときのStackTraceに固有の文字が出てきそうなので、
protected override void OnTextChanged(EventArgs e) { base.OnTextChanged(e); if (Environment.StackTrace.Contains("System.Windows.Forms.Design.ControlDesigner.InitializeNewComponent")) //(DesignMode && { return; } MessageBox.Show(Environment.StackTrace); }
個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
すべての返信
-
とりあえずVS2008,2010,2012では、貼り付けたときのStackTraceに固有の文字が出てきそうなので、
protected override void OnTextChanged(EventArgs e) { base.OnTextChanged(e); if (Environment.StackTrace.Contains("System.Windows.Forms.Design.ControlDesigner.InitializeNewComponent")) //(DesignMode && { return; } MessageBox.Show(Environment.StackTrace); }
個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
-
『コンポーネントを配置したその瞬間』ここだけで判断すると、
FormのControlAddedイベントで処理するのはいかがでしょうか。
※コントロール側からでなくForm側から見る。protected override void OnControlAdded(ControlEventArgs e) { base.OnControlAdded(e); MessageBox.Show(e.Control.Name); foreach (Control control in GetControls(e.Control)) { MessageBox.Show(control.Name); } } /// <summary> /// 指定コントロール配下のコントロール一覧を取得します。 /// </summary> /// <param name="parent"></param> /// <returns></returns> private List<Control> GetControls(Control parent) { List<Control> result = new List<Control>(); foreach (Control control in parent.Controls) { result.Add(control); result.AddRange(GetControls(control)); } return result; }
力技臭いですが・・・
- 回答の候補に設定 佐伯玲 2013年3月25日 0:13
-
基本的にこのあたりの仕組みが変わることはなさそうなので、今回の例では問題ないと思いますが、この手の実装依存で判断する手法は、将来性に対してリスクがあるのでご注意ください。
一応、DesignerAttribute、ControlDesigner といった仕組みは存在するので、頑張ればできるような気はします。
確実性があるかどうかはわかりませんが、たとえば、こういったコードでも目的のことをある程度満たせそうに見えます。
ただ、本来の TextBoxDesigner を使えていないので、微妙な挙動を示す場面があるかもしれません。public class SampleTextBoxDesigner : ControlDesigner { public override void InitializeNewComponent(System.Collections.IDictionary defaultValues) { var targetControl = ((SampleTextBox)Control); targetControl._isInitializing = true; try { base.InitializeNewComponent(defaultValues); targetControl.Text = string.Empty; } finally { targetControl._isInitializing = false; } } } [Designer(typeof(SampleTextBoxDesigner))] public class SampleTextBox : TextBox { internal bool _isInitializing; protected override void OnTextChanged(EventArgs e) { base.OnTextChanged(e); if (_isInitializing) return; MessageBox.Show("tes5t"); } }
// これが最良とは思っていません。
// Site プロパティ周りで、初期化中とかとれないんかなぁと思ったものの、たどり着かず。- 編集済み AzuleanMVP, Moderator 2013年3月25日 14:04