2013-11-04 61 views
1

好吧,讓我試着解釋一下。如何強制更新MVVM中的UI?

我有一個應用程序,我可以觸發某種掃描過程。這個掃描過程啓動(只是一個數字)10個背景的工作人員做些事情。後(再次,只是一個數字)5秒我想

  • 殺死所有的後臺工作人員(我使用CancelAsync爲)
  • 做一些計算與我從所有這些
  • 的獲得了數據
  • 更新UI,使得顯示的數據,並實現一些按鈕(這些按鈕通過ViewModel命令約束稱爲PerformUpdateCommand和他們的IsPerformUpdateAllowed一個CanExecute屬性。當我的任務完成IsPerformUpdateAllowed依賴屬性設置。

我想我會做:

  • 觸發背景工人後,使用5秒的間隔定時器調度。
  • DispatcherTimer「ticks」我計算數據並將屬性IsPerformUpdateAllowed設置爲true或false。

這只是基本上按預期工作(用戶界面保持響應,...)只是一個小問題:用戶界面沒有被更新(按鈕未啓用)。只要我將窗口放入背景並返回到前景中,該命令即會啓用,並且IsPerformUpdateAllowed屬性也將設置爲true。另外,按下按鈕後(禁用狀態),它將被啓用。

所以,雖然我正確設置了依賴項屬性,但UI並未對此更改做出反應。

有人知道爲什麼嗎?有趣的是,我還在用戶界面中設置了一些文本到一個標籤 - 這個文本被正確更新。只是告訴命令CanExecute的屬性不會觸發UI更新。

定時器初始化代碼。

 _scanTimer = new DispatcherTimer(); 
     _scanTimer.Interval = new TimeSpan(0, 0, 0, 3); 
     _scanTimer.Tick += delegate 
     { 
      // After the timer has elapsed (some time passed), cancel all scans and update the result 
      _scanTimer.Stop(); 
      UpdateScanResults(); 
      CancelNormalScans(false); 
     }; 
     _scanTimer.Start(); 

代碼的命令是如何結合到WPF元件(按鈕實際上是一個超鏈接):

  <Label Grid.Row="1" Grid.Column="1"> 
       <Hyperlink Command="{Binding ReadSettingsCommand}"> 
        <TextBlock Text="{Binding Source={StaticResource Loc}, Path=Labels.ReadSettings}"></TextBlock> 
       </Hyperlink> 
      </Label> 

下面是命令

public RelayCommand ReadSettingsCommand 
    { 
     get 
     { 
      return _readSettingsCommand 
       ?? (_readSettingsCommand = new RelayCommand(ExecuteReadSettings,() => IsScannedDeviceAvailable && !IsUpdateInProgress)); 
     } 
    } 

的代碼是代碼實際上依賴於兩個依賴項屬性IsScannedDeviceAvailable AND NOT IsUpdateInProgress。兩者都是依賴屬性。

更新:我剛剛讀到綁定到CanExecute屬性只是一次。如果你想讓它重新生效,你需要在命令上調用RaiseCanExecuteChanged。這可以起作用,但它有點麻煩,因爲現在我需要在兩個屬性中的一個發生更改時手動調用它。其實我想讓它自動處理。關於如何更輕鬆地完成這些任何想法? CanExecute和屬性之間是否存在某種單向綁定的方法?

+0

什麼是您的IsPerformUpdateAllowed DependencyProperty? – markmnl

+0

您的ICommands不會引發CanExercuteChanged事件。 – Aron

+0

@Aron:有沒有比手動調用RaiseCanExecuteChanged更好的方法? –

回答

3

每當您設置了IsScannedDeviceAvailable/IsUpdateInProgress時,您的VM都會調用RaiseCanExecuteChanged。或者我個人最喜歡創建自己的實現ICommand,因爲它非常簡單。

public class FooCommand : ICommand 
{ 
    private bool _canExecute; 
    private Action _delegate; 
    public event EventHandler CanExecuteChanged; 
    public new bool CanExecute 
    { 
     get 
     { 
      return _canExecute; 
     } 
     set 
     { 
      _canExecute = value; 
      if(CanExecuteChanged != null) 
       CanExecuteChanged(); 
     } 
    } 

    public void Execute(object parameter) 
    { 
     _delegate(); 
    } 

    bool ICommand.CanExecute() 
    { 
     return CanExecute; 
    } 

    public FooCommand(Action action) 
    { 
     _delegate = action; 
    } 
} 
+0

謝謝,這應該工作。然而,我實際上想以相反的方式編碼整個事物。一旦命令的所有條件都滿足,它應該自動啓用。 –

0

如果你正在引發基礎上的屬性Command.CanExecute()的變化,你也可以撥打CommandManager.InvalidateRequerySuggested()迫使CanExecute()進行重新評估。

+0

這將不是非常有效,因爲它將不得不評估所有的命令。 –