【W(wǎng)PF】Command 自定義命令

在使用 MVVM 結(jié)構(gòu)的 WPF 程序中,ViewModel 對 View 的響應(yīng)是通過 Command (命令)來完成的。比如用戶點(diǎn)了某個(gè)按鍵,使得與該按鍵相綁定的命令被觸發(fā),而該命令又是在 ViewModel 中被定義的,于是就完成了一次 View 對 ViewModel 的調(diào)用。

WPF 和 C# 語言的高級用法,比如委托、反射、事件等等,是緊密聯(lián)系的,所以學(xué)習(xí) WPF 時(shí)需要有一定的 C# 基礎(chǔ)。

雖然官方提供了一些常用命令,但本文還是著重于自定義命令的用法。

?? 方法一 從頭開始創(chuàng)建自定義命令

第一步:創(chuàng)建命令

命令有兩大要素:做什么、能做嗎。自定義命令首先要繼承自 ICommand

    class CustomCommand : ICommand
    {
        //當(dāng)能不能做發(fā)生變化時(shí)會觸發(fā)的事件(必須要實(shí)現(xiàn))
        public event EventHandler CanExecuteChanged;

        public void Execute(object param)  //做什么(必須要實(shí)現(xiàn))
        {
            ExecuteAction?.Invoke(param);
        }

        public bool CanExecute(object param)  //能做嗎(必須要實(shí)現(xiàn))
        {
            if (CanExecuteAction != null)
                return CanExecuteAction(param);
            return false;
        }

        public Action<object> ExecuteAction { get; set; }
        public Func<object, bool> CanExecuteAction { get; set; }
    }

如上所示,ICommand 的后代有三個(gè)東西必須要實(shí)現(xiàn),而最后兩個(gè) ExecuteActionCanExecuteAction 是比較推薦的寫法。

在本例中,Execute() 方法是 ICommand 認(rèn)定的用來執(zhí)行命令的方法,ExecuteAction 是對該方法的一項(xiàng)委托,于是外部使用者(ViewModel)只需設(shè)置這份委托,而不需染指 Execute() 方法。

第二步:完成ViewModel

接下來把這個(gè)命令類放在 ViewModel 中使用:

//先實(shí)例化這個(gè)命令(這是屬于ViewModel的命令,等下要被送到View中去)
public CustomCommand MyCommand { get; set; }

public void DoSomething(object param){
    //這個(gè)命令真正要做的事情
}
public bool CanDoSomething(object param){
    return true;  //判斷能否做這個(gè)事情,大部分時(shí)候返回true就行了
}
public MyViewModel(){
    //在ViewModel的構(gòu)造函數(shù)中,完成對命令的設(shè)置
    MyCommand = new CustomCommand();
    MyCommand.ExecuteAction = new Action<object>(this.DoSomething);
    MyCommand.CanExecuteAction = new Func<object, bool>(this.CanDoSomething);
}

ViewModel 中定義了兩個(gè)函數(shù),分別對應(yīng)命令的“做什么”、“能做嗎”,并通過委托的方式告訴命令。

第三步:完成View

剩下的就是 View 中的內(nèi)容了:

先要加入命名空間,才能獲得我們的 ViewModel。這里把命名空間設(shè)為vm
<Window xmlns:vm="clr-namespace:MyApp.ViewModel" ... />
    <Grid>
        <Grid.DataContext>
            <vm:MyViewModel>  <!--把第二步中的ViewModel當(dāng)作DataContext-->
        </Grid.DataContext>

        <Button Content="Click here" Command="{Binding MyCommand}" />
    </Grid>
</Window>

在 View 的 xaml 文件中,首先把 ViewModel 當(dāng)作它的 DataContext (畢竟 ViewModel 其實(shí)就是 View 的 Model)。然后直接在按鈕上用 Binding 的方式綁定命令。于是當(dāng)用戶點(diǎn)擊按鈕時(shí),這個(gè)命令就會被觸發(fā)。

命令被觸發(fā)時(shí),它會先調(diào)用自己的 CanExecute() 方法,這個(gè)方法在第一步中調(diào)用 CanExecuteAction 這個(gè)委托,這份委托又在第二步中綁定了 CanDoSomething() 方法……經(jīng)過一番長途跋涉之后終于調(diào)用了 DoSomething() 方法 ??。

感受:如果按照老辦法,按鈕響應(yīng)只需設(shè)一個(gè) OnClick 的方法就成了,簡單清爽,完全不必大費(fèi)周章搞這么多事??僧?dāng)程序到了一定規(guī)模,舊的思路就使維護(hù)變得難以維系。做界面還是應(yīng)該養(yǎng)成良好的習(xí)慣


?? 方法二 使用自帶的 RoutedUICommand

先創(chuàng)建一個(gè)命令:

public static class CustomCommands
{
    public static readonly RoutedUICommand ExitCommand = new RoutedUICommand(
        "quit app", 
        "ExitCommand",
        typeof(CustomCommands),
        new InputGestureCollection() { 
            new KeyGesture(Key.W, ModifierKeys.Control)  //可以為它綁定快捷鍵
        });
}

然后為“做什么”和“能做嗎”定義兩個(gè)方法:

public void ExitCommand_Execute(object sender, ExecutedRoutedEventArgs e)
{
    //在這里寫執(zhí)行命令的具體內(nèi)容(要做什么事)
    e.Handled = true;
}
public void ExitCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
    e.CanExecute = true;  //在這里判斷該命令能否執(zhí)行
    e.Handled = true;
}

最后在 xaml 里面進(jìn)行綁定:

<Window.CommandBindings>
    <CommandBinding Command="local:CustomCommands.ExitCommand" 
        CanExecute="ExitCommand_CanExecute" 
        Executed="ExitCommand_Execute"/>
</Window.CommandBindings>

<Button Content="Exit" Command="local:CustomCommands.ExitCommand"/>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容