2011-01-23 2 views
0

誰もがこのコードで間違っていることを誰かに教えてもらえますか?Cでスレッドセーフのプログレスバーを作る方法は?私は間違って何をしていますか?

それは

_DialogueThread.Start(); 

に、「クロススレッド操作ではない有効な」例外がスローされますが、私は

_progressDialogue = new Progresser{Owner = _owner, StartPosition = FormStartPosition.CenterParent}; 

から「所有者」を削除した場合、例外がスローされ文句を言わないが、progressDialougeが表示されますすぐに隠された。

私はprogressDialouge.Ownerを別のスレッドで作成された親フォームに設定すると、なぜこのエラーがスローされるのか理解しています。しかし、なぜ私はしないときにフォームが消える?私は間違って何をしていますか?

おかげで、あなたのアクション(ボタンのクリック)で

class Sampleer : BackgroundWorker 
{ 
    private Progresser _progressDialogue; 
    private Thread _DialogueThread; 
    private Form _owner; 
    private bool _SampleSuccess; 

    public Sampleer(Form owner) 
    { 
     _owner = owner; 
     _progressDialogue = new Progresser{Owner = _owner, StartPosition = FormStartPosition.CenterParent}; 
     _progressDialogue.Closed += ProgressDialogueClosed; 
     WorkerReportsProgress = true; 
     WorkerSupportsCancellation = true; 
     DoWork += Sampleer_DoWork; 
     RunWorkerCompleted += Sampleer_RunWorkerCompleted; 
     ProgressChanged += Sampleer_ProgressChanged; 
    } 

    private void Sampleer_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 

     //UPDATE STATUS CODE IS HERE 

    } 

    void ProgressDialogueClosed(object sender, EventArgs e) 
    { 
     CancelAsync(); 
     Dispose(); 
    } 

    void Sampleer_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     //FINISH PROCESS 
    } 


    void Sampleer_DoWork(object sender, DoWorkEventArgs e) 
    { 

     _DialogueThread = new Thread(_progressDialogue.Show); 
     _DialogueThread.Start(); 


     //DO LONG PROCESS HERE 
    } 
} 
+0

この場合、なぜBackgroundWorkerを継承していますか? – Pierreten

+0

私はSampleerBackgroundWorkerを作成していますが、作業中は進行状況バーで新しいフォームをポップします – Amir

+0

メインのUIスレッドから作業をオフロードするためにバックグラウンドワーカーを作成します。あなたは、この非UIスレッドでUI要素を作成するべきではありません。 – djeeg

答えて

0

はいdecycloneが正しいと、コード内でこの溶液へのアプローチには多くの間違いがあります。

BackgroundWorkerタイプを継承していますが、独自のイベントに登録していますか? 代わりに、クラス内のイベントを発生させるメソッドをオーバーライドします。 例:DoWorkを購読する代わりに、OnDoWorkメソッドをオーバーライドします。

フォーム(バックグラウンドタスクを実行する場合)が別のフォーム(BackgroundWorkUINotification)を表示し、BackgroundWorkerスレッドでバックグラウンドタスクを開始するサンプルアプリケーションを作成しました。 BackgroundWorkUINotificationは、フォームのCancelButtonがクリックされたときにメインフォームに通知します。

通知されると、メインフォームが通知を閉じ、バックグラウンドタスクをキャンセルします。以下

コード:BackgroundWorkUINotificationフォーム

public partial class BackgroundWorkUINotification : Form 
    { 
     public event EventHandler CancelClicked; 

    public BackgroundWorkUINotification() 
    { 
     InitializeComponent(); 

     // call code to animate progress bar.. 
     // probably in another BackgroundWorker that reports progress..    

     this.cancelButton.Click += HandleCancelButtonOnClick; 
    } 


    protected virtual void OnCancelClicked() 
    { 
     if (CancelClicked != null) 
      this.CancelClicked(this, EventArgs.Empty); 
    } 

    private void HandleCancelButtonOnClick(Object sender, EventArgs e) 
    { 
     this.OnCancelClicked(); 
    } 
} 

メインフォーム

public partial class Form1 : Form 
{ 
    private BackgroundWorker backgroundWorker; 

    public Form1() 
    { 
     InitializeComponent(); 
    } 

    private void Form1_Load(object sender, EventArgs e) 
    { 
     this.backgroundWorker = new BackgroundWorker(); 
     this.backgroundWorker.DoWork += HandleBackgroundWorkerOnDoWork; 
     this.backgroundWorker.RunWorkerCompleted += HandleBackgroundWorkerOnRunWorkerCompleted; 
     this.backgroundWorker.WorkerSupportsCancellation = true; 
    } 

    private void HandleDataRequest() 
    { 
     // show UI notification... 
     BackgroundWorkUINotification backgroundWorkUINotification = new BackgroundWorkUINotification(); 
     backgroundWorkUINotification.CancelClicked += HandleBackgroundWorkUINotificationOnCancelClicked; 
     backgroundWorkUINotification.Show(this); 

     // start the background worker 
     this.backgroundWorker.RunWorkerAsync(); 
    } 

    private void HandleBackgroundWorkUINotificationOnCancelClicked(Object sender, EventArgs e) 
    { 
     // UI notification Form, Cancelled 
     // close the form... 
     BackgroundWorkUINotification backgroundWorkUINotification = (BackgroundWorkUINotification)sender; 
     backgroundWorkUINotification.Close(); 

     // stop the background worker thread... 
     if (backgroundWorker.IsBusy) 
      backgroundWorker.CancelAsync(); 
    } 

    private void HandleBackgroundWorkerOnRunWorkerCompleted(Object sender, RunWorkerCompletedEventArgs e) 
    { 

    } 

    private void HandleBackgroundWorkerOnDoWork(Object sender, DoWorkEventArgs e) 
    { 
     // do some work here.. 
     // also check for CancellationPending property on BackgroundWorker 
    } 
} 
+0

これは本当に助けてくれてありがとう! – Amir

1

は、私は、進行状況ダイアログを作成し、バックグラウンドワーカーをオフに解雇でしょう。その後、バックグラウンドワーカーはProgressChangedイベントのダイアログに戻って報告します。

public partial class MainWindow : Window { 

    private void btnDoSomething_Click(object sender0, RoutedEventArgs e0) { 

     _progressDialogue = new Progresser{Owner = _owner, StartPosition = FormStartPosition.CenterParent}; 
     _progressDialogue.Closed += ProgressDialogueClosed; 
     _progressDialogue.Show(); 

     BackgroundWorker worker = new BackgroundWorker(); 
     worker.WorkerReportsProgress = true; 
     worker.DoWork += delegate(object sender, DoWorkEventArgs e) { 
      DoSomething(); 

      e.Result = result; 
     }; 
     worker.ProgressChanged += delegate(object sender, ProgressChangedEventArgs e) { 
      progressDialogue.Update() 
     }; 
     worker.RunWorkerCompleted += delegate(object sender, RunWorkerCompletedEventArgs e) { 
      progressDialogue.Close() 
     }; 
     worker.RunWorkerAsync(new CustomArgs() { 
      SomeValue = txtValue.Text, 
     }); 
    } 
} 
1

あなたのアプローチにはいくつか誤りがあります。私はそれらを一つずつ指摘しましょう。

  • あなたはBackgroundWorkerを継承します。それは結構です。しかし、内部に別のスレッドを作成します(_DialogueThread)。必要はありません。 DoWork()メソッドは別のスレッドで実行されます。

  • UI要素を別のスレッドで作成/使用/操作します。さて、いつも覚えています。 Threadは、UI要素を決して作成しません。それは逆です。 UI要素はThreadを作成します。あなたの場合のProgresserは新しいThreadを作成するか、BackgroundWorkerを使用して必要なバックグラウンド作業を行う必要があります。

`

+0

あなたの入力をありがとう – Amir

関連する問題