プロが教える店舗&オフィスのセキュリティ対策術

Visual Studio 2005 C#.netです。

クラスからフォームをバックグラウンドスレッド起動して、そのフォームを起動したクラスから正常にフォームを消去させたい(終了)させたいのですが、どうすればいいのでしょうか?

現在、以下のプログラムにて実現していますが、Abortで強制終了させているのでDispose();
も行われていないと思います。
呼び出し側からアクションを起こしてAbortではなく、スレッド側から正常に終了させたいのです。
また、Showメソッドだとフォーム表示が一瞬で終わってしまうのは何故でしょうか?
よろしくお願いいたします。

クラス:
public class FormDisplayClass
{
//スレッド
private System.Threading.Thread thread;

//フォーム
private TestForm TF = new TestForm();//フォームは別に存在するとします。

//表示メソッド
public void Show()
{
//スレッド設定
this.thread = new System.Threading.Thread(
new System.Threading.ThreadStart(FormShow));
//バックグラウンド
this.thread.IsBackground = true;
//スタート
this.thread.Start();
}

/// <summary>
/// スレッドを終了させる。
/// </summary>
public void Close()
{
this.thread.Abort();
}

/// <summary>
/// フォームを表示させる
/// </summary>
private void FormShow()
{
this.SWD.ShowDialog();//表示
     (Showだと表示を持続できない)
this.SWD.Dispose();
}
#endregion
}

呼び出し側:

FormDisplayClass FDC = new FormDisplayClass();

   private 表示メソッド
{
FDC.Show();
}

   private 終了メソッド
{
sw.Close();
}
}

よろしくお願いします。

A 回答 (6件)

FormDisplayClassにスレッドの実行関数を用意します


またフォームが開いているかどうかを表すフラグも用意します

// フォームを閉じるためのフラグ
private Bool bFlag;

// スレッド実行関数
protected void myProc()
{
  // フォームを表示
  this.TF.Show();
  // フォームが破棄されるまでループを回る
  while ( !this.TF.IsDisposed )
  {
    // 他のスレッド止めないための処理
    Application.DoEvents();
    // 破棄される前に 閉じろフラグが立った時
    if ( bFlag && !this.TF.IsDisposed )
    {
      this.TF.Close();
    }
  }
}

public void show()
{
  // フォームが破棄されている場合
  if ( !this.TF.IsDisposed )
  {
    this.TF = new TestForm();
  }
  bFlag= false;
  //スレッド設定
  this.thread = new System.Threading.Thread( new System.Threading.ThreadStart(myProc));
  //バックグラウンド
  this.thread.IsBackground = true;
  //スタート
  this.thread.Start();
}

public void Close()
{
  // フラグをセットするだけにする
  bFlag = true;
  // 次回のmyProc内のループでフラグがチェックされてフォームが閉じる
  // フォームが閉じるとwhileループを抜け myProcも終了
  // この時点でthreadが終了する
}

といった具合でしょう ・・・
    • good
    • 0
この回答へのお礼

早速のアドバイスありがとうございます。
うまく行きました。
ありがとうございました。

このフラグ&ループのリソース使用については、
負担がかからないものなのでしょうか。

お礼日時:2010/11/19 09:01

> DoEventsをWhileでループさせる場合、Sleepを入れないとビジー状態になるという件ですが、


> そのままにしておくとどのような弊害が起こるのでしょうか?
少々勘違いがあるようです

Sleepを入れる、入れないではなくて DoEventsを入れるかどうかなのです
DoEventsを入れずにwhileループをまわしても TestForm側のイベント処理等が何もされなくなってしまうという現象が起きます
これはスレッドが実行すべき項目が whileループの中だけにとどまってしまうためです

SleepやWaitOneなどで他の処理へCPUの力を振り分ける機会を多くしてやればいいかと思いますよ
    • good
    • 0
この回答へのお礼

解説有難うございます。

少しずつ理解出来てきたと思います。
とりあえずは、フラグ&ループの形式で目的は達しているので、
これで行きたいと思います。

色々ご親切にありがとうございました。
また、何かの時はよろしくお願いいたします。

お礼日時:2010/11/22 13:05

メインスレッド側で何かのプロシージャやイベントの中で


ビジーループ(大きなループ処理でメッセージポンプを止めてしまうようなもの)があるとカクカクした動きはSleepを小さくしても直らないかもしれません


AutoResetEventについては
クラスのメンバーとして宣言しておいて
スレッドのメインループの中でSleepを使用している部分と置き換えます

class FomDisp
{
private AutoResetEvent myEvent;
private Thread thread;
private TestForm TF;

// コンストラクタ
Public FormDisp()
{
thread = new Thread( new ThreadStart( myProc ) );
myEvent = new AutoResetEvent( false );
}

// スレッドのメインループ
private void myProc()
{
  TF.Show();
  // イベントがセットされるまで 100ms待機する
  while ( !myEvent.WaitOne( 100, false ) ) {
    Application.DoEvents();
  }
  TF.Close();
}

public void show()
{
  TF = new TestForm();
  thread.Start();
}

publicvoid close()
{
  // メインループを終了するためにセットする
  myEvent.Set();
}

}

といった具合です ・・・
    • good
    • 0
この回答へのお礼

アドバイス有難うございます。

AutoResetEventsを試してみたところ、
動作はしましたが、ご指摘の通り、動作が遅い状況となりました。

一つ教えて頂きたいのですが、
DoEventsをWhileでループさせる場合、
Sleepを入れないとビジー状態になるという件ですが、
そのままにしておくとどのような弊害が起こるのでしょうか?
また、5mmSec程度のsleepをループに噛ます事でこの弊害を
回避する事が出来ていると言えるのでしょうか?

大変恐縮ですが、よろしくお願いいたします。

お礼日時:2010/11/22 09:13

スプラッシュウィンドウを表示させたいのであれば



そのアプリのメインフォームのコンストラクタでスプラッシュウィンドウ用のフォームをインスタンス化してShowしてしまえばいいように思います ・・・

で、メインフォームのShownイベントでそのスプラッシュをCloseすればいいのでは ・・・
と感じますがいかがなのでしょう

カクカクした動きになるのは Sleepの具合だと思いますので 500を小さくしてみましょう
または Thread.Sleepで待つのではなくてAutoResetEventのWaitOneとかで待つようにするとかでしょうか

メインフォーム側のループの中に 100毎とか500毎などに
Application.DoEvents() を実行してみるとか ・・・
    • good
    • 0
この回答へのお礼

お返事が遅くなって申し訳ありません。

AutoResetEventについて調べいるのですが、
どこにどう挿入すれば良いのかを理解するのにはもう少し時間がかかりそうです。

とりあえず、Sleepの値を小さくしてなんとか目的は果たせそうですので、
これで凌いでいこうと思います。

有難うございました。

お礼日時:2010/11/21 18:13

何をどのようにしたいのかの情報がわれわれ回答者にはまったくありません



スレッド仕立てにしてFormを管理ってのはあんまりしないと思います
逆に Formの中にスレッドをこしらえて このスレッドから来るイベントやメッセージによりFormの描画を変更する
といったことはよくやる手ですよ

2005以降なら BackgroundWorkerなどがありますし ・・・

この回答への補足

アドバイス有難うございます。
情報が欠落していました。失礼しました。
目的の動作ですが、

起動に時間のかかる同C#アプリケーションがあり、そのアプリケーションが起動するまでの間(shownイベントまで)
「起動中です」という、例えばウインドウズが起動中に出すような動きのある画面を出しておきたいのです。
ただ、この機能は他にも転用可能としてクラス化し、当然、呼び出す側はインスタンス、
show,close等の簡単な記述で完了させたいと言う事が目的です。
今回は、この表示(form)をクラスからThreadで起動し、表示をしようと考えておりました。

目的を記述するのはマナー違反かと思い自粛していた次第です。
何か、アドバイスありましたらよろしくお願いいたします。

補足日時:2010/11/19 20:19
    • good
    • 0

スレッド実行ループがビジーループに近い状態ですのでちょっとまずいですね



protected void myProc()
{
  // フォームを表示
  this.TF.Show();
  // フォームが破棄されるまでループを回る
  while ( !this.TF.IsDisposed )
  {
    // 他のスレッド止めないための処理
    Application.DoEvents();
    // 破棄される前に 閉じろフラグが立った時
    if ( bFlag && !this.TF.IsDisposed )
    {
      this.TF.Close();
    }
    // ここに追加
    Thread.Sleep( 500 );
  }
}

といった感じで Sleepを挿入してみてください
    • good
    • 0
この回答へのお礼

アドバイスありがとうございます。

sleepを挿入してみたのですが、
表示しているフォーム上に、
オブジェクトを動かす動作をしているのですが、
これがsleepの影響を受けてうまく動きません。

そもそも、Thread上でフォームの表示を行うのは
イレギュラーなのでしょうか?

お礼日時:2010/11/19 17:45

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!