漫长的过程,绑定更新和 UI 冻结

Long process, binding update and UI frozen

我的 WPF/C# 程序使用在特定序列中调用的不同方法。 每个方法都绑定到UI,经过很长的过程才显示一些数据。 我正在使用调度程序,因为被调用的方法在另一个线程中。 我还想在不冻结 UI 的情况下执行此过程,例如能够取消该过程并自由替换 window。

我的问题是 UI 根本没有更新(进度条,计算步骤)并且取消按钮直到计算结束才起作用。 事实上,o不知道如何立即取消一般序列,即使挂起的长过程没有完成。

我不是 100% 确定使用正确的方法,有没有人有更好的解决方案或任何建议?

例如

   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;
}

谢谢

在方法 Work 中,您正在后台线程上执行。每次调用 dispatcher.BeginInvoke 时,传递给此方法的 action 将在 UI 线程[=23] 上执行=]。看看你现在在做什么?再看看这段代码

// 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

您的代码不断进入后台线程以在 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);
    });
}