长进程,绑定更新和UI冻结

时间:2017-06-15 13:22:06

标签: c# wpf binding dispatcher

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

由于

2 个答案:

答案 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);
    });
}