DOBON.NET DOBON.NETプログラミング掲示板過去ログ

インスタンスへのポインタ

環境/言語:[環境/言語 : WindowsXP / VS2005 C# .net2.0]
分類:[.NET]

お世話になります。
refでの引数渡しの仕様について教えて下さい。
以下のような操作をしました。

@ Form1にてPanel継承クラスの"A"インスタンス生成
A Form1.Contorls.Add(A)
B Form1からForm2のインスタンスを生成し、この際に参照渡し(ref)にて
  Form2に"A"インスタンスを渡す
C Form2.Control.Add(A)
D Form2.Close()

BorCの辺りで、Form1に表示されていた"A"インスタンスは表示が消えて
CにてForm2に"A"インスタンスが表示されます。
Dで"A"へのポインタはForm1からもForm2からも消失するようです。

質問1
B、Cの時点ではForm1, Form2とも"A"インスタンスへのホ゜インタを持っていると
認識しておりましたが、"A"インスタンスの表示がForm1上から消えるのは
何故でしょうか?(Contorlクラスの排他制御仕様?)

質問2
Form2からの"A"インスタンスへのポインタはForm2.Close()の時点で
消滅しても良いのですが、
Form1のホ゜インタは失いたくありません。可能でしょうか?

以上宜しく御願いします。
■No30204に返信(siroさんの記事)

CでControls.Addすることにより親が変わるから。

やりたい事を実現するには
別にインスタンスを作成して、内容をコピーする必要があります。
■No30204に返信(siroさんの記事)
> 質問1
> B、Cの時点ではForm1, Form2とも"A"インスタンスへのホ゜インタを持っていると
> 認識しておりましたが、"A"インスタンスの表示がForm1上から消えるのは
> 何故でしょうか?(Contorlクラスの排他制御仕様?)

Control とそれの継承クラスは、別の Controls に Add される際、元の Controls からは Remove される実装になっています。
従って、両方が親になることはありません。


> 質問2
> Form2からの"A"インスタンスへのポインタはForm2.Close()の時点で
> 消滅しても良いのですが、
> Form1のホ゜インタは失いたくありません。可能でしょうか?

もしも、一つのコントロールを親を変えて使い回したいなら、Close や Dispose する前に Controls.Remove を使って取り外してください。


// Control のインスタンスと呼ぶのはよいのですが、ポインタとは呼びません。
// この機会に用語を見直してください。
■No30213に返信(Azuleanさんの記事)
> ■No30204に返信(siroさんの記事)

> Control とそれの継承クラスは、別の Controls に Add される際、元の Controls からは Remove される実装になっています。
> 従って、両方が親になることはありません。

このような仕様なのですね。了解しました。
元親(Form1)、今親(Form2)ともインスタンス"A" への参照は保持している
ようなのですが、親は一人でなければいけない理由とは
何なのでしょうか・・・

> もしも、一つのコントロールを親を変えて使い回したいなら、Close や Dispose する前に Controls.Remove を使って取り外してください。

了解しました。

> // Control のインスタンスと呼ぶのはよいのですが、ポインタとは呼びません。
> // この機会に用語を見直してください。

了解しました。
解決済み!
■No30217に返信(siroさんの記事)
> 元親(Form1)、今親(Form2)ともインスタンス"A" への参照は保持している
> ようなのですが、親は一人でなければいけない理由とは
> 何なのでしょうか・・・

この場合、Form1.A と Form2.A は同一インスタンスへの参照を指します。
参照先のコントロールは一つなので、親も当然一つです。

同じインスタンスなのに、変数の宣言場所によって、
A.Parent や A.FindForm() の結果が変化してしまっては不自然ですよね。


Form1 と Form2 の両方で所有したいなら、shu さんが回答されたように、
インスタンスも 2 つ用意する必要があります。

あるいは、一つのインスタンスを 2 つのフォームで交互に使いまわすなら、
Azulean さんが書かれたように、所有権の移設が必要です。



>>もしも、一つのコントロールを親を変えて使い回したいなら、Close や Dispose する前に Controls.Remove を使って取り外してください。
> 了解しました。

たとえば下記では、Form2 に Controls.Add されている textBox1 を
Form1.textBox1 という変数にもセットしています。


TextBox textBox1 = null;
private void button1_Click(object sender, EventArgs e)
{
    using (Form2 form2 = new Form2())
    {
        this.textBox1 = (TextBox)form2.Controls.Find("textBox1", true)[0];
        this.textBox1.TextChanged += delegate { this.Text = this.textBox1.Text; };
        form2.ShowDialog();
    }
    // this.Controls.Add(this.textBox1);   // これはできない
    this.textBox1 = null;
}

最後の Controls.Add の行を実行すると、ObjectDisposedException が発生します。
これは ShowDialog した form2 が閉じられたときに、その上にある textBox1 も
一緒に破棄されてしまうからです。


Form2 終了時に、textBox が破棄されないようにしたいのであれば、
  using (Form2 form2 = new Form2())
  {
      this.textBox1 = (TextBox)form2.Controls.Find("textBox1", true)[0];
      this.textBox1.TextChanged += delegate { this.Text = this.textBox1.Text; };
      form2.FormClosing += delegate { form2.Controls.Remove(this.textBox1); };
      form2.ShowDialog();
  }
のように、終了前に Remove で取り外す必要がありますし、あるいは、
Form2 終了時に、textBox の所有権を Form1 に移したいのであれば、

    using (Form2 form2 = new Form2())
    {
        this.textBox1 = (TextBox)form2.Controls.Find("textBox1", true)[0];
        this.textBox1.TextChanged += delegate { this.Text = this.textBox1.Text; };
        form2.FormClosed += delegate { Controls.Add(this.textBox1); };
        form2.ShowDialog();
    }

のように、コンテナの変更(Controls の 再Add)が必要となります。



>>> B Form1からForm2のインスタンスを生成し、この際に参照渡し(ref)にて
>>>   Form2に"A"インスタンスを渡す
インスタンスを渡すだけなら、値渡しで十分ではないでしょうか。

fm = new Form2(this.A);   // 「public Form1(Panel a)」を呼び出す。

DOBON.NET | プログラミング道 | プログラミング掲示板