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

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

C# と VB.NET の入門サイト

Re[2]: 別ウインドウ(スレッド)からコントロール操作(デリゲート)


(過去ログ 17 を表示中)

[トピック内 5 記事 (1 - 5 表示)]  << 0 >>

■6639 / inTopicNo.1)  別ウインドウ(スレッド)からコントロール操作(デリゲート)
  
□投稿者/ asuka (18回)-(2007/08/21(Tue) 13:33:27)

分類:[C#] 

いつもお世話になっております。

親ウインドウにテキストボックス1つとボタンが1つあります。

ボタン押下で子ウインドウを生成します。

子ウインドウにもテキストボックスとボタンが1つづつあります。



子ウインドウのテキストボックスに入力した文字を、子ウインドウにあるボタン押下で親ウインドウのテキストボックスに表示する作業をデリゲートを使って行いたいと考えております。



■親ウインドウ側
// 親ウインドウのデリゲート用関数は以下の通りです。
public bool CallBack_SetTextBox1( string strText1 )
{
 try
 {
  textBoxParent.Text = strText1;
  return true;
 }
 catch( Exception ex )
 {
  return false;
 }
}

// ボタン押下で子ウインドウ生成
FormChild fChild = new FormChild( );
fChild.ShowDialog( this );



■子ウインドウ側
// デリゲートの定義
public delegate bool CallBack_SetTextBox1( string strText1 );
// デリゲートの宣言
private CallBack_SetTextBox1 m_callbackSetText1;


// フォームのロードで以下の処理を記載
// デリゲートの実態を確保
FormParent fp = new FormParent();
m_callbackSetText1 =
new CallBack_SetTextBox1( fp.CallBack_SetTextBox1 );


// ボタン押下で以下の処理を記載
m_callbackSetText1( textBox1.Text );


---
.NET2.0から別スレッドからのコントロールはInvokeを使うような記事をみつけましたが、

そのほとんどが、親ウインドウ内で生成したスレッドから使用するもので、

子ウインドウから操作するような記事を見つけることが出来ずに苦戦しております。



このソースで実行しますと、特にエラーは発生しませんが、

親ウインドウのテキストボックスに子ウインドウで入力したテキストが反映されないままです。
(親ウインドウ内でメッセージボックスで表示すると子ウインドウで入力した文字が表示されるが、テキストボックスには反映されない。)

どのようにすれば親ウインドウに反映出来るか御教授頂ければ幸いです。




以前、親ウインドウから子ウインドウを生成する際に、

FormChild fChild =
new FormChild( new FormChild .SetTextBox1( CallBack_SendText1 ) );
fChild.ShowDialog( this );

のように、子ウインドウのコンストラクタにデリゲートの関数を引数もたせていまいたが、

今回は子ウインドウで生成したいと考えております。

このような方法はそもそも実装不可能なのでしょうか?


引用返信 編集キー/
■6642 / inTopicNo.2)  Re[1]: 別ウインドウ(スレッド)からコントロール操作(デリゲート)
□投稿者/ 囚人 (135回)-(2007/08/21(Tue) 14:13:31)
まず、ウィンドウが別だからといってスレッドが別なわけではありません。従って、単純に考えてください。

次に、以下のコードでは親ウィンドウではなく、全く別のウィンドウを作成しているだけです。

>// フォームのロードで以下の処理を記載
>// デリゲートの実態を確保
>FormParent fp = new FormParent();
>m_callbackSetText1 =
>new CallBack_SetTextBox1( fp.CallBack_SetTextBox1 );

要は

>// ボタン押下で以下の処理を記載
>m_callbackSetText1( textBox1.Text );

を次のようによいです。

FormParent fp = (FormParent)this.Owner;
fp.textBoxParent.Text = textBox1.Text

デリゲートとかいりません。
引用返信 編集キー/
■6643 / inTopicNo.3)  Re[1]: 別ウインドウ(スレッド)からコントロール操作(デリゲート)
□投稿者/ Hongliang (171回)-(2007/08/21(Tue) 14:15:16)
Hongliang さんの Web サイト
少々誤解があるようです。
お示しになったコードにはスレッド成分が含まれていません、よね?
スレッド越しのコントロールの操作にデリゲートが使用される(ことが多い)のは事実ですが、デリゲート自体はスレッドとは無関係で、飽くまで処理の委譲のためのものです。
一般に、複数のウィンドウがあってもそれらは同一のスレッドで動作させます。新しくフォームを表示したら自動的に別スレッドが立ち上がってということはありません。

と言うことで、話は単純にオブジェクト間の処理の主体の話になります。
今回は子フォームが親フォームに処理の実装を委譲する形ですね。

さて、子フォームの処理をご覧ください。
委譲するための親フォームをどうやって取得していますか?

new してますよね。このキーワードは、文字通り「新しい」インスタンスを作成するためのものです。
新しく作られたものですから、既にあるものとは別物です。つまり、既に表示中の親フォームとは別物なのです。
別物のフォームなので、それが何をどうしようと既に表示中の親フォームには何の影響も及ぼせません。

子フォームが既存の親フォームに処理を委譲するなら、なんとかして既存の親フォームを取得する必要があります。
例えば子フォームに親フォーム型のプロパティを持たせ、子フォームを表示するときに親フォームが自身を設定するといった方法が考えられます。

んが、それ以前にこういうコードは望ましくありません。以前に書いてたと言うコンストラクタでデリゲート渡す方がよほどマシです。
そもそも、子フォームが親フォームの呼び出すべきメソッドを知っているなら、デリゲートの出番はないですよね? 直接そのメソッドを呼び出せばいいんですから。
m_callbackSetText1( textBox1.Text );
よりも
fp.SetTextBox1( textBox1.Text );
の方が直感的でしょう。
デリゲートが意味を持つのは、そのデリゲートに関連付けられたメソッドを知らない状況です。
ですから何を関連付けるか(つまりデリゲートを作成すること)は親フォームの仕事です。
// 端的に言えば、「子は親を知っているべきではない」ってことになるんですが……まあ省略。

ところで、デリゲートを使った仕組みの一つにイベントがあります。コントロールのクリックイベントとかです。
今回の目指すところが「子フォームに親フォームテキストを設定してもらうこと」ではなく「何か子フォームに変化があったことを親フォームに教えたい(親フォームの TextBox が変更されるのはその結果)」ということなら、イベントを使った方がいいでしょう。
引用返信 編集キー/
■6646 / inTopicNo.4)  Re[1]: 別ウインドウ(スレッド)からコントロール操作(デリゲート)
□投稿者/ まどか (358回)-(2007/08/21(Tue) 14:19:08)
まず今おこなっていることの目的がよくわかりません。
おこないたい処理とデリゲートとの関係です。
つまり、「デリゲートとは」、書かれている動作の実現、のどちらが目的なのか。

で、普通に考えれば
子ウィンドウがイベントを発生させる、または、
親が子に参照を渡して子が親の公開メンバにアクセスする
になると思います。
#デリゲートを使うなということではありません。※場面は限られますが


> fChild.ShowDialog( this );

モーダル表示ですので、fChildが閉じるまで親側のメッセージはストップします。
したがって、子側で親のコントロールの値を書き換えても描画されません。

> // フォームのロードで以下の処理を記載
> // デリゲートの実態を確保
> FormParent fp = new FormParent();

もうひとつの別の親を作ってますけど。。。。。

> .NET2.0から別スレッドからのコントロールはInvokeを使うような記事をみつけましたが、

スレッド?
今回の場合、親も子も同じメインUIスレッドですよ。

> そのほとんどが、親ウインドウ内で生成したスレッドから使用するもので、
> 子ウインドウから操作するような記事を見つけることが出来ずに苦戦しております。

そもそも親とか子とかではありません。
あるスレッドで作成されたControlへ別のスレッドからアクセスする際は、
Controlが作成されたスレッド上で動作させなくてはいけないということです。

> 親ウインドウのテキストボックスに子ウインドウで入力したテキストが反映されないままです。
> (親ウインドウ内でメッセージボックスで表示すると子ウインドウで入力した文字が表示されるが、テキストボックスには反映されない。)

先に指摘したとおりですが、親のインスタンスが二ついるはず。。。
引用返信 編集キー/
■6653 / inTopicNo.5)  Re[2]: 別ウインドウ(スレッド)からコントロール操作(デリゲート)
□投稿者/ asuka (19回)-(2007/08/21(Tue) 14:53:05)
レスありがとうございます。

反映されない原因は分かりました、別インスタンス(親をもうひとつ)を作成していた為だと解釈しました。

と、御指摘を頂いてそもそも実装事態が悪いことに痛感しました。



囚人さんのおっしゃるとおり、そもそも

FormParent fp = (FormParent)this.Owner;
fp.textBoxParent.Text = textBox1.Text

とすることで実装可能なのですが、

コントロールをPrivateでなくPublicにしなければならないところに違和感を感じましたので、
(理由はないです。)

デリゲートを使うのかな?と思って実装を進めておりました。
(正直まだよくデリゲートが分かっていないです。)



また今回の背景に、最後に記載させて頂いたとおり、

以前、親ウインドウから子ウインドウを生成する際に、

FormChild fChild =
new FormChild( new FormChild .SetTextBox1( CallBack_SendText1 ) );
fChild.ShowDialog( this );

とすることでエリゲートで実装出来ることが分かっていたので、

子ウインドウ側から現状の親スレッドを生成して出来ないか、

という疑問がありました。



Hongliangさんがおっしゃるとおり、なんとかして既存の親フォームを取得したいと思っておりました。

結果的には

fp.SetTextBox1( textBox1.Text );

とすることで動作することは確認できましたが、構成事態よろしくないなと改めて実感しました。




それと大きな勘違いは、皆様が御指摘して下さったように、

別フォームを生成すると別スレッドが立ち上がるものだと思っておりました。




まどかさんの仰るとおり、まずはスレッドについての覚え違いと、

別インスタンスを作っていることに恥ずかしさを覚える限りです。

今回は囚人さんにアドバイス頂いたとおり、シンプルに実装したいと思います。

ありがとうございました。

解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -