我的WPF / C#程序使用在特定序列中调用的不同方法。 每个方法都绑定到UI,在长时间的过程后显示一些数据。 我正在使用调度程序,因为被调用的方法在另一个线程中。 我也希望在不冻结UI的情况下执行此过程,例如可以取消该过程并自由替换窗口。
我的问题是UI根本没有更新(进度条,计算步骤),取消按钮在计算结束前没有运行。 实际上,即使待处理的长进程没有完成,也不知道如何立即取消一般序列。
我不是百分百肯定使用正确的方式,有没有人有更好的解决方案或任何建议?
离。
public void CalculationCommand()
{
var bkw = new BackgroundWorker()
bkw.DoWork += Work;
bkw.RunWorkerAsync(Dispatcher.CurrentDispatcher);
}
public void Work(object sender, DoWorkEventArgs e)
{
var dispatcher = e.Argument as Dispatcher;
var dispatcherPriority = DispatcherPriority.Background;
Action action;
action = () =>
{
UpdateStatut(StatutsInformation.Pending);
};
dispatcher.BeginInvoke(action, dispatcherPriority);
ViewModel1 viewModel1 = null;
action = () =>
{
UpdateProgress(10, "Sampling calculations");
viewModel1 = Application.GetEchantillonnage();//Long process
};
dispatcher.BeginInvoke(action, dispatcherPriority);
List<double> lengthList = null;
action = () =>
{
UpdateProgress(20, "Length calculations");
lengthList = AlgorithmLibrary.LengthCalculations(viewModel1);//Long process
};
dispatcher.BeginInvoke(action, dispatcherPriority);
ViewModel2 viewModel2 = null;
action = () =>
{
UpdateProgress(30, "Engine calculations");
viewModel2 = Application.GetEngine();//Long process
AlgorithmLibrary.EngineCalculations(viewModel2);//Long process
var FilteredLength = AlgorithmLibrary.LengthFilter(lengthList);//Long process
}; dispatcher.BeginInvoke(action, dispatcherPriority);
///... Others actions executed incrementing the progress value to 100%
action = () =>
{
UpdateStatut(StatutsInformation.Finished);
};
dispatcher.BeginInvoke(action, dispatcherPriority);
}
private void UpdateStatut(StatutsInformation statutInformation)
{
ViewModelLoading.StatutInformation = statutInformation;
}
private void UpdateProgress(int value, string label)
{
ViewModelLoading.Progress = value;
ViewModelLoading.Step = label;
}
由于
答案 0 :(得分:2)
在方法Work
内部,您正在后台线程上执行。每次拨打dispatcher.BeginInvoke
操作时,您都会在 UI线程 上执行此方法。看看你现在在做什么?再看一下这段代码
// Here, we are on a background thread
action = () =>
{
// This action is NOT executing yet! We are just defining it.
UpdateProgress(10, "Sampling calculations");
// This is going to execute on the thread that executes this action!
viewModel1 = Application.GetEchantillonnage();//Long process
};
// here, we are still on the background thread, but we are telling the
// dispatcher to marshall the action onto the UI thread to execute it!
dispatcher.BeginInvoke(action, dispatcherPriority);
您正在UI线程上进行长期工作:/
但解决方案很简单。只需将您的工作拉出来并将其保留在后台线程中。这里的代码相同,但按预期工作(除非代码中出现其他问题)
action = () => UpdateProgress(10, "Sampling calculations");
dispatcher.BeginInvoke(action, dispatcherPriority);
viewModel1 = Application.GetEchantillonnage();//Long process
答案 1 :(得分:0)
您的代码不断进入后台线程,以便在UI线程上执行长时间运行的任务。 Dispatcher.BeginInvoke将委托编组回UI线程。
试试这个:
private void RunOnUI(Action uiAction, DispatcherPriority dispatcherPriority = DispatcherPriority.Background)
{
dispatcher.BeginInvoke(uiAction, dispatcherPriority);
}
public void Work(object sender, DoWorkEventArgs e)
{
var dispatcher = e.Argument as Dispatcher;
var dispatcherPriority = DispatcherPriority.Background;
Action action;
runOnUI(() =>
{
UpdateStatut(StatutsInformation.Pending);
});
ViewModel1 viewModel1 = null;
RunOnUI(() =>
{
UpdateProgress(10, "Sampling calculations");
});
viewModel1 = Application.GetEchantillonnage();//Long process
List<double> lengthList = null;
RunOnUI(() =>
{
UpdateProgress(20, "Length calculations");
});
lengthList = AlgorithmLibrary.LengthCalculations(viewModel1);//Long process
ViewModel2 viewModel2 = null;
RunOnUI(() =>
{
UpdateProgress(30, "Engine calculations");
};
viewModel2 = Application.GetEngine();//Long process
AlgorithmLibrary.EngineCalculations(viewModel2);//Long process
var FilteredLength = AlgorithmLibrary.LengthFilter(lengthList);//Long process
///... Others actions executed incrementing the progress value to 100%
RunOnUI(() =>
{
UpdateStatut(StatutsInformation.Finished);
});
}