C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

ログ内検索
  • キーワードを複数指定する場合は 半角スペース で区切ってください。
  • 検索条件は、(AND)=[A かつ B] (OR)=[A または B] となっています。
  • [返信]をクリックすると返信ページへ移動します。
キーワード/ 検索条件 /
検索範囲/ 強調表示/ ON (自動リンクOFF)
結果表示件数/ 記事No検索/ ON
大文字と小文字を区別する

No.90071 の関連記事表示

<< 0 >>
■90071  Re[3]: ユーザーコントロールの使い方
□投稿者/ 魔界の仮面弁士 -(2019/02/04(Mon) 13:47:10)
    2019/02/04(Mon) 14:32:50 編集(投稿者)

    No90070 (ルパン さん) に返信
    >   pnlSub.Controls.Remove(pnlSub.Controls[0]);
    >   pnlSub.Controls[0].Dispose();

    そのコードは正しくありません。
    1 行目が指している [0] と 2 行目が指している [0] が
    別のコントロールを指していることに注意してください。


    提示のコードだと、pnlSub 上の子コントロールが【奇数個】の場合に
    最後の 1 個が Remove されないことになってしまいます。
    ※例外:ArgumentOutOfRangeException

    また、【偶数個】であった場合、一見するとすべて Remove されるように
    見えますが、実際には偶数・奇数いずれの場合にも、
    「半数は Remove しただけ(Dispose していない)」
    「半数は Dispose しただけ(自動的に Remove される)」
    という動作に陥っていることに注意してください。



    代案1:削除対象のコレクションと列挙用のコレクションを分ける

    Control[] children = pnlSub.Controls.OfType<Control>().ToArray();
    foreach (Control c in children)
    {
     pnlSub.Controls.Remove(c);
     c.Dispose();
    }


    代案2:子アイテムを変数等に保持しておき、コレクションから除去後に破棄する
    while (pnlSub.Controls.Count > 0)
    {
     using (pnlSub.Controls[0])
     {
      pnlSub.Controls.RemoveAt(0);
     }
    }


    代案3:後ろから前に Dispose する
    for (int i = pnlSub.Controls.Count - 1; i >= 0; i--)
    {
     // Dispose されると自動的に Remove される
     pnlSub.Controls[i].Dispose();
    }



    > ネットで調べたら 「UserControl の後処理は Dispose で行う」とあったので、

    親コントロールが破棄される際には、それに先んじて
    子コントロールが破棄されますので、Disposed イベント中には
    他のコントロール(もちろん Label にも)アクセスすることはできません。

    故にたとえば Dispose 時には、「子コントロールそのもの」に
    アクセスするのではなく、予め保持しておいた
    「子コントロールが持っていた値」を使って処理するようにします。


    新規プロジェクトに下記を貼り、実行してフォームを閉じてみてください。


    using System.Diagnostics;
    public partial class Form1 : Form
    {
     private UserControl uc;
     public Form1()
     {
      InitializeComponent();
      Controls.Add(uc = new UC() { Dock = DockStyle.Fill });
     }
    }

    public class UC : UserControl
    {
     private Label lbl;
     private string _labelText = null;
     private string LabelText { get { return _labelText; } }
     public UC()
     {
      Controls.Add(lbl = new Label() { Text = "lbl", Dock = DockStyle.Fill });
      
      // Label が破棄された後でも Text を拾えるよう、保持しておく
      lbl.TextChanged += delegate { _labelText = lbl.Text; };
      _labelText = lbl.Text;

      //
      lbl.Disposed += delegate
      {
       Debug.WriteLine("Label.Disposed");
       Debug.WriteLine(" UserControl.Disposing = " + this.Disposing);
       Debug.WriteLine(" UserControl.IsDisposed = " + this.IsDisposed);
       Debug.WriteLine(" Label.Disposing = " + lbl.Disposing);
       Debug.WriteLine(" Label.IsDisposed = " + lbl.IsDisposed);
       Debug.WriteLine(" Label.Text = [" + lbl.Text + "]");
       Debug.WriteLine(" LabelText = [" + this.LabelText + "]");
      };
      this.Disposed += delegate
      {
       Debug.WriteLine("UserControl.Disposed");
       Debug.WriteLine(" UserControl.Disposing = " + this.Disposing);
       Debug.WriteLine(" UserControl.IsDisposed = " + this.IsDisposed);
       Debug.WriteLine(" Label.Disposing = " + lbl.Disposing);
       Debug.WriteLine(" Label.IsDisposed = " + lbl.IsDisposed);
       Debug.WriteLine(" Label.Text = [" + lbl.Text + "]");
       Debug.WriteLine(" LabelText = [" + this.LabelText + "]");
      };
     }
    }


    ---- 実行結果 ----
    Label.Disposed
     UserControl.Disposing = True
     UserControl.IsDisposed = False
     Label.Disposing = True
     Label.IsDisposed = False
     Label.Text = []
     LabelText = [lbl]
    UserControl.Disposed
     UserControl.Disposing = True
     UserControl.IsDisposed = False
     Label.Disposing = False
     Label.IsDisposed = True
     Label.Text = []
     LabelText = [lbl]
記事No.90068 のレス /過去ログ155より / 関連記事表示
削除チェック/



<< 0 >>

パスワード/

- Child Tree -