おそらくスレッド関連のMVPソリューションに問題があります。私はCompact Framework 3.5を実行していて、C#を使用しています。私はOpenNETCFを使うことができるので、BackgroundWorkerは私に利用可能です。バックグラウンドワーカー(例外が発生したMVP)
ソケットを使用してWebサーバーに接続するコード(MyClient
)があります。コードはサーバーに接続し、ユーザーがデータを停止するまでデータ(無限にストリーム)をダウンロードします。データのダウンロードは無限であるため、スレッドで実行する必要があります。これが問題の原因です。 MyClient
オブジェクトには、enum On
,Off
、Connecting
と表される状態があります。 を編集します。わかりやすくするために、MyClient.Start()を呼び出すと、サーバーに接続します。その後、その接続を取得し、Thread Runで使用するために保存して、データを絶えずダウンロードします。したがって、Stop()が呼び出されると、MyClient内で使用されるスレッドにStopを通知するためにboolフラグを取得する必要があります。明快にするために、以下のバージョンを短縮しました。
public void Start()
{
//...
//Code to Connect to server...
stream = _connection.GetStream();
//...
//Code to send/receive data to confirm connection...
State = State.On;
//Start thread to read data constantly until stopped by user setting "_continueReadingData = false"
_continueReadingData = true;
Thread readData = new Thread(ReadData);
readData.IsBackground = true;
readData.Start();
//Note readData uses the stream variable saved above
}
ビューは_presenter.TurnOn();
とプレゼンターを呼び出します。プレゼンターは_model.Start();
でモデルを呼び出します。このアイデアは、MyClientコードが開始され、ステータスが変更されたことを報告し、ユーザーが停止をクリックするまでバックグラウンドで無限に実行されます。 View
は、UIコンポーネントでInvoke/BeginInvoke呼び出しによって保護されています。
私のモデルのコードサンプルを以下に添付しました。もともとは普通のスレッドを使っていましたが、以下のようにコメントアウトされています。この2つの問題は、ビューに到達するすべてのUIスレッドにマーシャリングするためにInvokeを使用する必要があります。また、発生した例外はUIスレッドに返されないため、処理できず、応用。これらは私が取り組もうとしている2つの問題です。
私はBackgroundWorker(.NET 2.0以降の通常のBackgroundWorkerと同じようにOpenNETCFで利用可能です)を試してみました。例外を処理し、下記のようにマーシャリングしました。しかし、これで私はそれを働かせることはできません。代わりに、状態が変更され、GUIに戻って報告されます。 Invokeが呼び出されても、InvalidOperationException - "Invoke or BeginInvoke cannot be called on a control until the window handle has been created"
という文句があります。いくつかの研究を行うと、スレッドのようにほとんど独自のコントロールセットが作成されているようです。この時点で私は混乱しています。
モデルのスレッドを適切に開始/終了させてバックグラウンドで実行し、処理対象のモデルに例外を戻し、UIスレッドに実行をマーシャリングする方法を教えてもらえますかすべてのコントロールでInvokeを使用する必要はありません。私はそれが可能でなければならないと確信しています。
public class Model
{
public event EventHandler DataChanged;
public event EventHandler ErrorRaised;
private MyClient _client = new MyClient();
public Model()
{
//Register to events
_client.StateChanged += ClientStateChanged;
//Setup current values
State = _client.State;
}
void ClientStateChanged(NTRIPClient client, NTRIPState newState)
{
State = newState;
}
private State _state;
public State State
{
get { return _state; }
set
{
if (_state != value)
{
_state = value;
if (DataChanged != null)
{
DataChanged(this, EventArgs.Empty);
}
}
}
}
public void Start()
{
//Thread thread = new Thread(_NTRIPClient.Start);
//thread.IsBackground = true;
//thread.Start();
BackgroundWorker bgWorker = new BackgroundWorker();
bgWorker.DoWork += _client.Start();
bgWorker.RunWorkerCompleted += bgWorker_RunWorkerCompleted;
}
void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if(e.Error != null)
{
if (ErrorRaised != null)
{
ErrorRaised(this, new ErrorEventArgs(e.Error));
}
}
}
}
http://stackoverflow.com/questions/1862590/how-to-update-gui-with-backgroundworkerで同様の議論があります。多分助けてくれるでしょう –
おかげでラルフ。私は投稿する前にそれを読んだ。私はそれが近いと思う。しかし、ProgressUpdated/Completedは、MyClientコードがバックグラウンドワーカーで実行されていることを知らないため、進捗状況を更新しないため、私には役に立ちません。また、GUIは、変化するプロパティ、すなわち状態を通知される必要がある。しかし、状態が変更されると、そのイベントはUI以外のスレッドで発生します。バックグラウンドワーカーを何とかサポートするためにクライアントを書き直す必要があったのだろうか? – JonWillis