1. 程式人生 > 其它 >【Prism005】命令

【Prism005】命令

簡介

命令提供了一種方便的方式來表示可以輕鬆繫結到UI中控制元件的動作或操作。它們封裝了實現動作或操作的實際程式碼,並有助於使其與檢視中的實際視覺表示分離。

建立命令

public class ArticleViewModel
{
    public DelegateCommand SubmitCommand { get; private set; }

    public ArticleViewModel()
    {
        SubmitCommand = new DelegateCommand<object>(Submit, CanSubmit);
    }

    
void Submit(object parameter) { //implement logic } bool CanSubmit(object parameter) { return true; } }

命令繫結

<Button Command="{Binding SubmitCommand}" CommandParameter="OrderId"/>

非同步命令示例

private DelegateCommand _submitAsyncClick;
public DelegateCommand SubmitAsyncClickCommand =>
            _submitAsyncClick 
?? (_submitAsyncClick = new DelegateCommand(async () => await SubmitAsync())); public async Task SubmitAsync() { await Task.Run(() => { Thread.Sleep(5000); }); }

複合命令

在許多情況下,檢視模型定義的命令將繫結到關聯檢視中的控制元件,以便使用者可以從檢視中直接呼叫該命令。但是,在某些情況下,您可能希望能夠從應用程式UI的父檢視中的控制元件呼叫一個或多個檢視模型上的命令。 例如,如果應用程式允許使用者同時編輯多個專案,則您可能希望允許使用者使用由應用程式工具欄或功能區中的按鈕表示的單個命令儲存所有專案。在這種情況下,“全部儲存”命令將呼叫檢視模型例項為每個專案實現的每個儲存命令,如下圖所示。 核心概念:CompositeCommand CompositeCommand類表示由多個子命令組成的命令。呼叫複合命令時,依次呼叫其每個子命令。在需要在UI中將一組命令表示為單個命令的情況下,或者在需要呼叫多個命令以實現邏輯命令的情況下,它非常有用。 CompositeCommand類維護子命令列表(DelegateCommand例項)。CompositeCommand類的Execute方法只是依次呼叫每個子命令的Execute方法。CanExecute方法類似地呼叫每個子命令的CanExecute方法,但如果無法執行任何子命令,CanExecute方法將返回false。換句話說,預設情況下,僅當所有子命令都可以執行時,才能執行CompositeCommand。

建立複合命令

通常,CompositeCommand在整個應用程式中共享,並且需要全域性可用。使用CompositeCommand註冊子命令時,在整個應用程式中使用CompositeCommand的同一例項,這一點很重要。這要求在應用程式中將CompositeCommand定義為單例。這可以通過使用依賴項注入(DI)或將CompositeCommand定義為靜態類來實現。 為了提高程式碼的可維護性和可測試性,建議使用依賴項注入方法。 方式1:使用依賴注入:
public interface IApplicationCommands
    {
        CompositeCommand SaveCommand { get; }
    }
 public class ApplicationCommands : IApplicationCommands
    {
        private CompositeCommand _saveCommand = new CompositeCommand();
        public CompositeCommand SaveCommand
        {
            get { return _saveCommand; }
        }
    }
public partial class App : PrismApplication
    {
        protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {
            containerRegistry.RegisterSingleton<IApplicationCommands, ApplicationCommands>();
        }
    }
public DelegateCommand UpdateCommand { get; private set; }

    public TabViewModel(IApplicationCommands applicationCommands)
    {
        UpdateCommand = new DelegateCommand(Update);
        applicationCommands.SaveCommand.RegisterCommand(UpdateCommand);
    }
方式2:使用靜態類
public static class ApplicationCommands
{
    public static CompositeCommand SaveCommand = new CompositeCommand();
}
 public DelegateCommand UpdateCommand { get; private set; }

    public TabViewModel()
    {
        UpdateCommand = new DelegateCommand(Update);
        ApplicationCommands.SaveCommand.RegisterCommand(UpdateCommand);
    }

繫結命令

建立CompositeCommand後,現在必須將它們繫結到UI元素以呼叫命令。 使用DI時,必須公開IAApplicationCommand以繫結到檢視。在檢視的ViewModel中,在建構函式中請求IAApplicationCommand,並將IAApplicationCommand型別的屬性設定為例項。
 public class MainWindowViewModel : BindableBase
    {
        private IApplicationCommands _applicationCommands;
        public IApplicationCommands ApplicationCommands
        {
            get { return _applicationCommands; }
            set { SetProperty(ref _applicationCommands, value); }
        }

        public MainWindowViewModel(IApplicationCommands applicationCommands)
        {
            ApplicationCommands = applicationCommands;
        }
    }
<Button Content="Save" Command="{Binding ApplicationCommands.SaveCommand}"/>
如果您使用的是靜態類方法,下面的程式碼示例將顯示如何將按鈕繫結到WPF中的靜態ApplicationCommand類。
<Button Content="Save" Command="{x:Static local:ApplicationCommands.SaveCommand}" />

登出命令

如前面的示例所示,子命令是使用CompositeCommand註冊的RegisterCommand方法。但是,如果您不再希望響應CompositeCommand,或者正在銷燬檢視/檢視模型以進行垃圾收集,則應使用CompositeCommand登出子命令。取消註冊命令方法。
public void Destroy()
    {
        _applicationCommands.UnregisterCommand(UpdateCommand);
    }
當不再需要檢視/檢視模型(準備好進行GC)時,必須從CompositeCommand中登出命令。否則將導致記憶體洩漏。

只在活動檢視中執行命令

父檢視級別的複合命令通常用於協調如何呼叫子檢視級別的命令。在某些情況下,您會希望對所有顯示的檢視執行命令,如前面描述的“全部儲存”命令示例所示。在其他情況下,您將希望僅在活動檢視上執行該命令。在這種情況下,複合命令將僅在被視為活動的檢視上執行子命令;它不會在非活動檢視上執行子命令。例如,您可能希望在應用程式的工具欄上實現一個縮放命令,該命令只縮放當前活動的專案,如下圖所示。 為了支援此場景,Prism提供了IActiveAware介面。IActiveAware介面定義了一個IsActive屬性,該屬性在實現者處於活動狀態時返回true,以及一個IsActiveChanged事件,該事件在活動狀態更改時引發。 您可以在檢視或檢視模型上實現IActiveAware介面。它主要用於跟蹤檢視的活動狀態。檢視是否處於活動狀態由特定控制元件內的檢視決定。例如,對於選項卡控制元件,有一個介面卡可將當前選定選項卡中的檢視設定為活動。 DelegateCommand類還實現了IActiveAware介面。通過在建構函式中為monitorCommandActivity引數指定true,可以將CompositeCommand配置為評估子DelegateCommand的活動狀態(以及CanExecute狀態)。當此引數設定為true時,CypIdCeMoMand類將在確定CANEXECUTE方法的返回值時以及在執行方法中執行子命令時考慮每個子Auto TeaCeMoMand的活動狀態。
public class ApplicationCommands : IApplicationCommands
    {
        private CompositeCommand _saveCommand = new CompositeCommand(true);
        public CompositeCommand SaveCommand
        {
            get { return _saveCommand; }
        }
    }
當monitorCommandActivity引數為true時,CompositeCommand類將顯示以下行為: CanExecute:僅當可以執行所有活動命令時才返回true。不活動的子命令將完全不被考慮。 Execute:執行所有活動命令。不活動的子命令將完全不被考慮。 通過在ViewModels上實現IActiveAware介面,當檢視處於活動或非活動狀態時,您將收到通知。當檢視的活動狀態更改時,可以更新子命令的活動狀態。然後,當用戶呼叫composite命令時,將呼叫活動子檢視上的命令。
 public class TabViewModel : BindableBase, IActiveAware
    {
        private bool _isActive;
        public bool IsActive
        {
            get { return _isActive; }
            set
            {
                _isActive = value;
                OnIsActiveChanged();
            }
        }

        public event EventHandler IsActiveChanged;

        public DelegateCommand UpdateCommand { get; private set; }

        public TabViewModel(IApplicationCommands applicationCommands)
        {
            UpdateCommand = new DelegateCommand(Update);
            applicationCommands.SaveCommand.RegisterCommand(UpdateCommand);
        }

        private void Update()
        {
            //implement logic
        }

        private void OnIsActiveChanged()
        {
            UpdateCommand.IsActive = IsActive; //set the command as active
            IsActiveChanged?.Invoke(this, new EventArgs()); //invoke the event for all listeners
        }
    }