2017-07-25 62 views
1

我在.NET 3.5和Visual Studio 2008下有一個WPF MVVM應用程序。視圖中的一些控件綁定到視圖模型的屬性,所以當這些屬性發生變化,它將通過INotifyPropertyChanged的實現通知給視圖。MVVM:在完成WPF NET 3.5中的線程池工作項後更新視圖的控件可見性

我開始時會在窗口中央出現一些說「正在加載...」的閃屏,並且在從數據庫請求某些數據時它會保持可見狀態。一旦從數據庫請求數據,我想要隱藏這種飛濺。

此飛濺在視圖模型中綁定到一個屬性「IsSplashVisible」,因此將屬性更新爲true,通知在beginnig中顯示的飛濺並將其設置爲false,通知要隱藏的飛濺。

在開始時將屬性「IsSplashVisible」設置爲true是沒有問題的,當排隊的工作項目完成時將屬性設置爲false時會出現問題。一旦將此屬性設置爲false,將通知控件(splash「正在加載...」),並嘗試隱藏但失敗,因爲這是創建它的人的不同線程,因此引發了典型的異常。那我該如何解決這個問題?

下面的代碼。

視圖模型

public class TestViewModel : BaseViewModel 
{ 
    private static Dispatcher _dispatcher; 
    public ObservableCollection<UserData> lstUsers 

    public ObservableCollection<UserData> LstUsers 
    { 
     get 
     { 
      return this.lstUsers; 
     } 

     private set 
     { 
      this.lstUsers= value; 
      OnPropertyChanged("LstUsers"); 
     } 
    } 

    private bool isSplashVisible = false; 

    public bool IsSplashVisible 
    { 
      get 
      { 
       return this.isSplashVisible; 
      } 

      set 
      { 
       if (this.isSplashVisible== value) 
       { 
        return; 
       } 

       this.isSplashVisible= value; 
       OnPropertyChanged("IsSplashVisible"); 
      } 
    } 

    public TestViewModel() 
    { 
     this.IsSplashVisible = true; 

     ThreadPool.QueueUserWorkItem(new WaitCallback((o) => 
     { 
      var result = getDataFromDatabase(); 
      UIThread(() => 
      { 
       LstUsers = result; 
       this.IsSplashVisible = false; <---- HERE IT FAILS 
      });    
     })); 
    } 

    ObservableCollection<UserData> getDataFromDatabase() 
    {    
     return this.RequestDataToDatabase(); 
    } 

    static void UIThread(Action a) 
    { 
     if(_dispatcher == null) _dispatcher = Dispatcher.CurrentDispatcher; 
     //this is to make sure that the event is raised on the correct Thread 
     _dispatcher.Invoke(a); <---- HERE EXCEPTION IS THROWN 
    } 
} 
+0

像@Clemens說,在你的代碼把'Application.Current.Dispatcher'納入這一點,所以它看起來像這樣'如果(_dispatcher == NULL)_dispatcher = Application.Current.Dispatcher;' – XAMlMAX

+0

@ XAMlMAX除了根本不具備該領域的意義。 *更好*總是調用'Application.Current.Dispatcher.Invoke(...)'。 – Clemens

+0

雖然它可能很牽強,但理論上可以在兩個不同的UI線程中創建兩個視圖模型實例。然後,一個靜態的Dispatcher字段將無法正常工作。 – Clemens

回答

4

Dispatcher.CurrentDispatcher不是UI線程的調度,因爲它

獲取調度當前正在執行的線程,並創建一個新的調度,如果一個是尚未與線程關聯。

您應該使用當前應用程序實例的調度:

ThreadPool.QueueUserWorkItem(o => 
{ 
    var result = getDataFromDatabase(); 

    Application.Current.Dispatcher.Invoke(() => 
    { 
     LstUsers = result; 
     IsSplashVisible = false; 
    });    
}); 

假設你TestViewModel構造函數被調用在UI線程,你可以寫它像如下所示,其中Dispatcher.CurrentDispatcher在UI線程中調用,而不是ThreadPool線程。但是,這個領域完全是多餘的。你總是可以撥打Application.Current.Dispatcher.Invoke()

public class TestViewModel 
{ 
    private readonly Dispatcher _dispatcher = Dispatcher.CurrentDispatcher; 

    public TestViewModel() 
    { 
     IsSplashVisible = true; 

     ThreadPool.QueueUserWorkItem(o => 
     { 
      var result = getDataFromDatabase(); 

      _dispatcher.Invoke(() => 
      { 
       LstUsers = result; 
       IsSplashVisible = false; 
      });    
     }); 
    } 

    ... 
} 
相關問題