2017-06-15 56 views
0

我的WPF/C#程序使用在特定序列中調用的不同方法。 每種方法都綁定到UI,在長時間處理後顯示一些數據。 我正在使用調度程序,導致被調用的方法在另一個線程中。 我也希望在不凍結UI的情況下執行此過程,例如可以取消過程並自由移動窗口。長進程,綁定更新和UI凍結

我的問題是根本沒有更新用戶界面(進度條,計算步驟),取消按鈕在計算結束後纔會運行。 事實上,即使掛起的長期過程沒有完成,也不知道如何立即取消一般序列。

我不是100%肯定會使用正確的方式,有沒有人有更好的解決方案或任何建議?

ex。

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

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 
+0

這裏的問題是,調用「viewModel1 = Application.GetEchantillonnage()」給出錯誤: – midget

+0

「因爲不同的線程擁有它調用線程不能訪問此對象」 @midget你正在做一些觸及界面的'GetEchantillonnage'方法。我不知道什麼或爲什麼,但你不需要那樣做。如果'GetEchantillonnage'需要來自用戶界面的東西,那麼**當你仍然在UI線程中時,首先獲取這些信息。然後重構此方法,以便在調用它時獲取此信息,並將整個事件移出Application對象。 – Will

+0

MVVM模式的重要組成部分是***將業務邏輯從用戶界面***中分離出來。如果你這樣做,那麼你沒有問題。但是你仍然將它們混合在一起('Application'沒有本地的'GetEchantillonnage'方法 - 你把它放在那裏)。重構刪除它。 – Will

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