簡體   English   中英

如何強制更新MVVM中的UI?

[英]How can I force update of the UI in MVVM?

好吧,讓我試着解釋一下。

我有一個應用程序,我可以觸發某種掃描過程。 這個掃描過程啟動(只有很多)10個后台工作人員做某事。 之后(再次,只是一個數字)5秒我想

  • 殺死所有后台工作人員(我正在使用CancelAsync)
  • 用我從他們所有的數據做一些計算
  • 更新用戶界面,使得顯示的數據,並啟用一些按鈕(這些按鈕是通過綁定ViewModel命令調用PerformUpdateCommand ,他們有一個CanExecute財產IsPerformUpdateAllowedIsPerformUpdateAllowed時,我的任務完成依賴屬性設置。

我以為我會做什么:

  • 觸發后台工作程序后,啟動一個間隔為5秒的調度程序計時器。
  • DispatcherTimer “ticks”時,我計算數據並將屬性IsPerformUpdateAllowed設置為true或false。

這基本上按預期工作(UI保持響應,......),只需要一個小小的hickup:UI沒有被更新(按鈕未啟用)。 只要我將窗口置於后台並返回到前台,就會啟用該命令,同時IsPerformUpdateAllowed屬性也會設置為true。 此外,按下按鈕后按下按鈕(處於禁用狀態),將啟用該按鈕。

因此,雖然我正確設置了依賴項屬性,但UI不會對此更改做出反應。

誰知道為什么? 有趣的是,我還在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>

這是Command的代碼

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

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

更新:我剛剛讀到,對CanExecute屬性的綁定只是一次。 如果要重新驗證,則需要在命令上調用RaiseCanExecuteChanged。 這可行,但它有點麻煩,因為現在每次兩個屬性中的一個更改時我需要手動調用它。 實際上我希望自動處理。 關於如何更容易地做到這一點的任何想法? 是不是有一些方法可以在CanExecute和屬性之間進行單向綁定?

每當設置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;
    }
}

如果基於屬性觸發Command.CanExecute()的更改,還可以調用CommandManager.InvalidateRequerySuggested()來強制重新評估CanExecute()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM