Eri*_*tas 6 .net c# wpf multithreading revit-api
我正在通过一个名为Revit的架构建模软件的API创建一个自定义加载项命令.我的命令可能需要一些时间才能完成,因此我想向用户显示一个带有进度条的窗口,因为它正在工作.
通常,如果我要创建这样的进度窗口,它将位于主UI线程上,并且正在完成的实际工作将在辅助工作线程上进行.但是,Revit要求对API的任何访问都是通过调用自定义命令的线程进行的.所以我必须在第二个线程上创建我的进度条.
我发现这篇博客文章是关于在一个单独的线程中启动WPF窗口,并基于我的解决方案.这是我的自定义命令类.
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();
}
}
Run Code Online (Sandbox Code Playgroud)
这是我的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);
}
Run Code Online (Sandbox Code Playgroud)
我的第一个问题一般是我做对了吗?它似乎有用,但我对多线程编程知之甚少,因为它知道它只是因为它今天起作用,并不意味着它明天会起作用.
其次,我想在我的进度窗口中添加一个取消按钮,以便能够取消该过程.做这个的最好方式是什么?我明白最终我会得到一个"cancelRequested"布尔标志,该标志由工作线程定期检查,但是如何从进度窗口线程设置它?
我看到的唯一改进是您在设置 yourAutoResetEvent和调用之间存在潜在的竞争条件Dispatcher.Run。我知道,因为我在使用多线程进度 UI 时遇到了这个问题。
修复的方法就是BeginInvoke后台调用Dispatcher。Dispatcher这将确保它在开始泵送事件后执行:
System.Windows.Threading.Dispatcher.Current.BeginInvoke(
new Func<bool>(_progressWindowWaitHandle.Set));
Run Code Online (Sandbox Code Playgroud)