2013-08-16 59 views
5

私は、RevitというアーキテクチャモデリングソフトウェアのAPIを使用してカスタムアドインコマンドを作成しています。私のコマンドは完了するまでに時間がかかることがあるので、進行中のバーが表示された状態でユーザーにウィンドウを表示したい。別のスレッドでWPF進捗ウィンドウを作成

通常、このようなプログレスウィンドウを作成する場合は、メインUIスレッド上にあり、実行される実際の作業はセカンダリワーカースレッドで行われます。ただし、Revitでは、カスタムコマンドを呼び出すスレッドを介してAPIにアクセスする必要があります。だから私は2番目のスレッドで進捗バーを作成する必要があります。

このブログの投稿はlaunching a WPF window in a separate threadで、私の解決策に基づいています。ここに私のカスタムコマンドクラスがあります。

public class SampleProgressWindowCommand : Autodesk.Revit.UI.IExternalCommand 
{ 

    private ProgressWindow progWindow; 
    internal static EventWaitHandle _progressWindowWaitHandle; 


    public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) 
    { 
     //Starts New Progress Window Thread 
     using (_progressWindowWaitHandle = new AutoResetEvent(false)) 
     { 

      //Starts the progress window thread 
      Thread newprogWindowThread = new Thread(new ThreadStart(ShowProgWindow)); 
      newprogWindowThread.SetApartmentState(ApartmentState.STA); 
      newprogWindowThread.IsBackground = true; 
      newprogWindowThread.Start(); 

      //Wait for thread to notify that it has created the window 
      _progressWindowWaitHandle.WaitOne(); 
     } 

     //Does some work that takes a long time 
     for (int i = 1; i <= 100; i++) 
     { 
      //Updates Progress 
      this.progWindow.UpdateProgress("Item " + i.ToString(), i, 100); 

      //Does some fake work 
      System.Threading.Thread.Sleep(700); 
     } 

     //closes the Progress window 
     progWindow.Dispatcher.Invoke(new Action(progWindow.Close)); 

     //Show Result to User 
     Autodesk.Revit.UI.TaskDialog.Show("Task", "Task Completed"); 
     return Result.Succeeded; 
    } 

    private void ShowProgWindow() 
    { 
     //creates and shows the progress window 
     progWindow = new ProgressWindow(); 
     progWindow.Show(); 

     //makes sure dispatcher is shut down when the window is closed 
     progWindow.Closed +=new EventHandler(progWindow_Closed); 

     //Notifies command thread the window has been created 
     _progressWindowWaitHandle.Set(); 

     //Starts window dispatcher 
     System.Windows.Threading.Dispatcher.Run(); 
    } 
} 

そして、ここでは私のProgressWindowクラス上のUpdateProgress()メソッドは

ある
public void UpdateProgress(string message, int current, int total) 
{   
    this.Dispatcher.Invoke(new Action<string, int, int>(

    delegate(string m, int v, int t) 
    { 
     this.progressBar1.Maximum = System.Convert.ToDouble(t); 
     this.progressBar1.Value = System.Convert.ToDouble(v); 
     this.messageLbl.Content = m; 
    }), 
    System.Windows.Threading.DispatcherPriority.Background, 
    message, current, total); 
} 

私の最初の質問は、一般的にある私はこの権利をしましたか?それはうまくいくように思えますが、今日は機能しているということを知るためにマルチスレッドプログラミングについて十分に知っていますが、明日は動作するとは限りません。

第2に、進行状況ウィンドウにキャンセルボタンを追加して、プロセスをキャンセルできるようにしたいと思います。これを行う最善の方法は何ですか?私は最終的に、作業スレッドによって定期的にチェックされる "cancelRequested"ブールフラグに終わることを理解していますが、これを進捗ウィンドウのスレッドからどのように設定するのですか?

+0

1 - AutoDeskで作業していますか?本当に? 2 - 適切なViewModelを作成し、ViewModelで2次ディスパッチャ・スレッドのプロパティ変更を発生させます。 –

+1

RevitはAutodeskによって作成されましたが、Autodeskではうまくいきません。通常、私が行うWPFはすべてMVVMですが、この例では簡単にするため、 '進行状況フォームのViewModelクラスを作成しませんでした。 –

+0

@EricAnastas私はこのスレッドが少し古いことを知っていますが、私は新しいと私の質問は非常にこの課題に近い見つけることができませんでした。外部イベントを開始したGUIを更新する方法はありますか? – Thibaud

答えて

3

唯一の改善点は、AutoResetEventを設定してからDispatcher.Runに電話をかける間に競合が発生する可能性があることです。マルチスレッドの進行状況UIを私自身が使用してこの問題に遭遇したので私は知っています。

これを修正する方法は、BeginInvokeに電話をして、Dispatcherとします。これにより、Dispatcherがイベントをポンピングした後に実行されます。

System.Windows.Threading.Dispatcher.Current.BeginInvoke(
    new Func<bool>(_progressWindowWaitHandle.Set)); 
関連する問題