Я создаю пользовательскую команду надстройки через API части программного обеспечения для архитектурного моделирования под названием Revit. Моя команда может занять некоторое время, поэтому я хочу показать пользователю окно с индикатором выполнения, когда оно работает.Создайте окно прогресса WPF в другом потоке
Как правило, если бы я должен был создать окно прогресса, подобное этому было бы на основном потоке пользовательского интерфейса, и фактическая работа выполнялась бы на вторичном рабочем потоке. Однако 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();
}
}
А вот метод UpdateProgress() в моем классе ProgressWindow
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 во вторичном потоке Диспетчера. –
Revit создан Autodesk, но я не работаю для Autodesk. Как правило, все WPF, которые я делаю, это MVVM, но для простоты в этом примере не был создан класс ViewModel для моей формы выполнения. –
@ EricAnastas Я знаю, что эта тема немного устарела, но я не нашел ее более новой, и мой вопрос очень близок к этой теме. Есть ли способ обновить GUI, который запустил внешнее событие? – Thibaud