- PR -

ソケットのAsyncCallbackデリゲート内でpictureBoxに表示したい

投稿者投稿内容
ヨンジュン
常連さん
会議室デビュー日: 2003/09/29
投稿数: 22
投稿日時: 2004-03-02 13:53
C#.NETのWindowsアプリケーションで非同期ソケット通信を行っています。
読み取りコールバックメソッド内で読み取った受信データ(画像)をFormのpictureBoxに
表示させようとしています。
読み取りコールバックメソッドは静的メソッドですので、受信バッファなどの有用な情報は小さなクラスを作成してBeginRecieveメソッドのオブジェクト引数として渡しています。
読み取りコールバックメソッド内でpictureBoxを参照させる為には、そのオブジェクト引数として渡すしか思いつかなくて、でもそうするためにはFormのpictureBoxの宣言を無理矢理static宣言に修正しないとコンパイルで
”静的でないフィールドSocketServer.Form1.pictureBox1でオブジェクトの参照が必要です。”
となってしまいます。
例え無理やりstatic宣言に修正してもFormのデザインを修正すると元に戻ってしまって、また上記のコンパイルエラーになってしまいます。

もっと良い方法はないでしょうか?


public class Form1 : System.Windows.Forms.Form
{
--- 省略---
public static System.Windows.Forms.PictureBox pictureBox1; ←無理矢理static
--- 省略---

private void InitializeComponent()
{
// this.pictureBox を無理矢理pictureBoxに修正

pictureBox1 = new System.Windows.Forms.PictureBoX();
pictureBox1.BackColor = System.Drawing.SystemColors.Desktop;
  this.Controls.Add(pictureBox1);
  }

public class StateObject // BeginRecieveに渡すオブジェクト
{
public Socket workSocket = null;
public const int BufferSize = 787496;
public byte [] buffer = new byte [BufferSize];
public PictureBox pictureBox =pictureBox1; ← 上記の定義をstaticにしないとここで’SocketServer.Form1.pictureBox1でオブジェクト参照が必要です’のエラーになる
}

  public static void AcceptCallback(IAsyncResult ar)
{
Socket listener = (Socket)ar.AsyncState ;
Socket handler = listener.EndAccept (ar);

StateObject state = new StateObject ();
state.workSocket = handler;
handler.BeginReceive (state.buffer , 0, StateObject.BufferSize , 0,
new AsyncCallback (ReadCallback), state);
}

public static void ReadCallback(IAsyncResult ar)
{
// Retrieve the state object and the handler socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState ;
Socket handler = state.workSocket ;

// Read data from the client socket.
int byteRead = handler.EndReceive (ar);
if( byteRead > 0 )
{
---省略---
state.pictureBox.Image = bmp2;  ←ここでForm1のpictureBoxに表示させたい
state.pictureBox.Invalidate ();
---省略---
}
}
}

Jubei
ぬし
会議室デビュー日: 2002/03/02
投稿数: 830
お住まい・勤務地: 関西
投稿日時: 2004-03-02 16:19
諸農です。

斜め読みですが、
「読み取りコールバックメソッドは静的メソッド」
とはどういうことなんでしょうか?
デリゲートではないのですが?


引用:

読み取りコールバックメソッド内でpictureBoxを参照させる為には、そのオブジェクト引数として渡すしか思いつかなくて、でもそうするためにはFormのpictureBoxの宣言を無理矢理static宣言に修正しないとコンパイルで



ちょっと意味がわからないのですが、
StateObjectクラスのコンストラクタに、フォームで利用しているPictureBoxの
参照を渡せば済むのではないでしょうか?何か別途ダメな理由があるのですか?

_________________
諸農和岳
Powered by Turbo Delphi & Microsoft Visual Studio 2005

十兵衛@わんくま同盟
http://blogs.wankuma.com/jubei/
ヨンジュン
常連さん
会議室デビュー日: 2003/09/29
投稿数: 22
投稿日時: 2004-03-02 16:45
すみません。私、なんか良く分かってないんだと思うんですが「読み取りコールバックメソッドは静的メソッド」っていうのはデリゲートなんですが、msdnで調べると
public static void AcceptCallback(IAsyncResult ar)
public static void ReadCallback(IAsyncResult ar)
のように static で宣言されていたものですから・・・そんな言い方はしないのかな?すみません。

こういう場合って、staticで宣言するものなのですか?

アドバイスのようにStateObjectクラスのコンストラクタに、フォームで利用している
PictureBoxの参照を渡そうとしてみたんですが、これもまたStateObjectのインスタンスを
作成するのも、public static void AcceptCallback()の中なので
FormのpictureBoxの参照の渡し方が分からないんです。

ぢゃん♪
大ベテラン
会議室デビュー日: 2003/06/12
投稿数: 208
お住まい・勤務地: 都内
投稿日時: 2004-03-02 17:05
引用:

ヨンジュンさんの書き込み (2004-03-02 16:45) より:
こういう場合って、staticで宣言するものなのですか?


絶対、ってことはないでしょう。
というか、たまたまその解説ページがstaticを使っているだけでしょう。
(たぶん非同期サーバー ソケットの例の解説では?)

ちなみに非同期サーバー ソケットの使用の例ではstaticでないacceptCallbackもありますし。
このケースなら、staticなんか取っ払ってもいいと思います。

[ メッセージ編集済み 編集者: ぢゃん♪ 編集日時 2004-03-02 17:10 ]
なちゃ
ぬし
会議室デビュー日: 2003/06/11
投稿数: 872
投稿日時: 2004-03-02 17:10
引用:

ヨンジュンさんの書き込み (2004-03-02 16:45) より:
すみません。私、なんか良く分かってないんだと思うんですが「読み取りコールバックメソッドは静的メソッド」っていうのはデリゲートなんですが、msdnで調べると
public static void AcceptCallback(IAsyncResult ar)
public static void ReadCallback(IAsyncResult ar)
のように static で宣言されていたものですから・・・そんな言い方はしないのかな?


サンプルがたまたまそう作ってあるだけだと思いますが…
静的なメソッドでは駄目な場合(という言い方も語弊があって、もっと正確にはインスタンスメソッドを使う必要がある場合)は、インスタンスメソッドを使えばいいんです。
とその前に、インスタンスメンバ(静的ではないメンバ)と静的メンバの意味の違いを理解する必要があります。というか、クラス、インスタンスについてちゃんと理解する必要があると思うんですけど、その辺は大丈夫ですか?書かれてるコードを見るとちょっとだけ微妙な線な気がしますが…
Jubei
ぬし
会議室デビュー日: 2002/03/02
投稿数: 830
お住まい・勤務地: 関西
投稿日時: 2004-03-02 18:06
諸農です。

引用:

アドバイスのようにStateObjectクラスのコンストラクタに、フォームで利用している
PictureBoxの参照を渡そうとしてみたんですが、これもまたStateObjectのインスタンスを
作成するのも、public static void AcceptCallback()の中なので
FormのpictureBoxの参照の渡し方が分からないんです。



実現方法は色々とあるとは思いますが。。
その前に、理解しておくことも色々ありますね。

コード:
public class StateObject
{ 
    public Socket workSocket = null; 
    public const int BufferSize = 787496; 
    public byte [] buffer = new byte [BufferSize]; 
    public PictureBox pb = null;
} 


public static void ReadCallback(IAsyncResult ar) 
{ 
    StateObject state = (StateObject)ar.AsyncState ; 
    Socket handler = state.workSocket ; 
    int byteRead = handler.EndReceive (ar); 
    //省略
    //ここでstate.pbを参照することで、間接的にフォーム上の
    //PictureBox(button1_Clickハンドラ内でStateObjectにセットしたpictureBox1)
    //を参照することになります。
    // ※ 別スレッドで動作するメソッド内からフォーム上のクラスを参照してもいいのか
    // ※ どうかは別問題ですが
} 

private void button1_Click(object sender, System.EventArgs e)
{
    Socket s = new Socket();//省略

    StateObject so = new StateObject();
    so.pb = this.pictureBox1; //ここでステートオブジェクトpbフィールドに
                              //フォーム上のPictureBoxの参照をセットする

    //非同期メソッドの呼び出し
    s.BeginReceive(so.buffer,0,so.BufferSize,0,new AsyncCallback(ReadCallback),so);
    //以下省略
}





_________________
諸農和岳
Powered by Turbo Delphi & Microsoft Visual Studio 2005

十兵衛@わんくま同盟
http://blogs.wankuma.com/jubei/
ヨンジュン
常連さん
会議室デビュー日: 2003/09/29
投稿数: 22
投稿日時: 2004-03-03 17:27
皆様ありがとうございます。

FormのPictureBoxのハンドルをFormのstaticメンバ変数にセットしておき、
そのstaticメンバ変数をStateObjectに持たせてみました。

public static IntPtr pictHandle;
pictHandle = this.pictureBox1;

public class StateObject
{
//省略
public IntPtr pictHandle = Form1.pictHandle;
}

public static void AcceptCallback(IAsyncResult ar)
{
Socket listener = (Socket)ar.AsyncState ;
Socket handler = listener.EndAccept (ar);

StateObject state = new StateObject ();
state.workSocket = handler;
handler.BeginReceive (state.buffer , 0, StateObject.BufferSize , 0,
new AsyncCallback (ReadCallback), state);
}

public static void ReadCallback(IAsyncResult ar)
{
StateObject state = (StateObject)ar.AsyncState ;
Socket handler = state.workSocket ;

int byteRead = handler.EndReceive (ar);
if( byteRead > 0 )
{
---省略---
PictureBox pictureBox = (PictureBox)FromHandle(static.pictHandle);
pictureBox.Image = bmp2;
pictureBox.Invalidate ();
---省略---
}
}

クラスとインスタンス、オブジェクト・・・C++との違いにまだまだ慣れずに
苦悩しています。
(C++も、完璧じゃないけど・・)

なちゃ
ぬし
会議室デビュー日: 2003/06/11
投稿数: 872
投稿日時: 2004-03-04 01:58
引用:

ヨンジュンさんの書き込み (2004-03-03 17:27) より:
FormのPictureBoxのハンドルをFormのstaticメンバ変数にセットしておき、
そのstaticメンバ変数をStateObjectに持たせてみました。


うーん、なんか最初のと本質的に変わってない気がするんですが…
引用:

public static void AcceptCallback(IAsyncResult ar)


まず、なんでこの辺をstaticにしてるんですか?
Formのインスタンスにアクセスする必要があるのなら、Formのインスタンスメソッドにすればいいと思うんですが…
Jubeiさんのサンプルのような流れでは出来ないですか?
単にコールバックメソッド(およびそこにアクセスする上のようなメソッド)をインスタンスメソッドにしてもいいですけど。
引用:

クラスとインスタンス、オブジェクト・・・C++との違いにまだまだ慣れずに
苦悩しています。
(C++も、完璧じゃないけど・・)


ていうか、C++でもおんなじです(オブジェクトの扱いにちょっと違いはありますが)。クラスとかインスタンスとかって部分はC++でも変わりません。

スキルアップ/キャリアアップ(JOB@IT)