我正在通過一個名爲Revit的建築建模軟件的API創建一個自定義加載項命令。我的命令可能需要一些時間才能完成,因此我想向用戶顯示帶有進度條的窗口。在另一個線程上創建一個WPF進度窗口
通常,如果我要創建一個像這樣的進度窗口,它將在主UI線程上,並且正在完成的實際工作將發生在輔助工作線程上。但是,Revit要求通過調用自定義命令的線程來訪問API。所以我必須在第二個線程上創建我的進度條。
我發現這篇博客文章關於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);
}
我的第一個問題是,一般沒有我這樣做對嗎?它似乎工作,但我對多線程編程足夠了解,知道僅僅因爲它今天有效,並不意味着它明天就會工作。
其次,我想添加一個取消按鈕到我的進度窗口能夠取消進程。做這個的最好方式是什麼?我明白,最終我會得到一個由工作線程定期檢查的「cancelRequested」布爾標誌,但是如何從進度窗口線程設置它?
1 - 您是否在使用AutoDesk?真? 2 - 創建一個合適的ViewModel並讓ViewModel在輔助Dispatcher線程中提升屬性更改。 –
Revit由Autodesk製作,但我不適用於Autodesk。通常,我所做的所有WPF都是MVVM,但爲了簡單起見,本示例沒有爲我的進度窗體創建ViewModel類。 –
@EricAnastas我知道這個線程有點舊,但我沒有找到新的,我的問題非常接近這個問題。有沒有辦法更新啓動外部事件的GUI? – Thibaud