WPF使用MVVM(二)-命令綁定


WPF使用MVVM(二)-命令綁定

上一節已經介紹了WPF的屬性綁定,這使得我們只需要指定界面的DataContext,然后就可以讓界面綁定我們的屬性數據呢。

但是上一節還遺留了一個問題就是我們的按鈕的Click方法,依然是寫在界面的后台中的,現在我們希望將按鈕的Click方法也采用綁定的形式。

原先是這樣的:

    <Button
        Grid.Row="3"
        Grid.ColumnSpan="2"
        Margin="20"
        Click="Button_Click"
        Content="更新一下信息"
        FontSize="30"
        FontWeight="Bold" />

希望變成這樣:

        <Button
            Grid.Row="3"
            Grid.ColumnSpan="2"
            Margin="20"
            Click="{Binding ClickAction}"
            Content="更新一下信息"
            FontSize="30"
            FontWeight="Bold" />

讓我們的MainWindowVM(ViewModel)也提供一個方法,讓我們綁定一下,這樣界面的數據和按鈕的點擊處理邏輯,都放到了橋梁ViewModel中了,界面看起來也很清爽。

Command

WPF呢,為了讓我們用MVVM的形式替換按鈕的點擊行為,給我們提供了一個Command的屬性,讓我們也可以像綁定屬性的方式,來綁定我們的點擊方法,具體的寫法如下:

        <Button
            Grid.Row="3"
            Grid.ColumnSpan="2"
            Margin="20"
            Command="{Binding ClickAction}"
            Content="更新一下信息"
            FontSize="30"
            FontWeight="Bold" />

之前寫的Button_Click方法也可以直接刪除了。

注意:Command屬性僅僅作為Click行為的綁定,其他行為,如鼠標移入、移出。。。等行為,要使用另外的MVVM方式進行綁定。(本文只介紹點擊行為,后續介紹其他行為的MVVM實現)

添加ClickAction的實現

上面我們也刪除了Button_Click方法,並且還給Button按鈕的Command屬性綁定了一個方法叫做ClickAction,接下來我們就要在MainWindowVM(ViewModel)中去添加這個方法。

要實現綁定的方法ClickAction,就需要用到ICommand接口,需要我們自己創建類型去實現接口的CanExecuteExecuteCanExecuteChanged,下面直接貼一下實現接口的代碼,需要新建一個類,名字我們取RelayCommand:

    public class RelayCommand : ICommand
    {
        /// <summary>
        /// 命令能否執行
        /// </summary>
        readonly Func<bool> _canExecute;
        /// <summary>
        /// 命令執行的方法
        /// </summary>
        readonly Action _execute;

        /// <summary>
        /// 命令的構造函數
        /// </summary>
        /// <param name="action">命令需執行的方法</param>
        /// <param name="canExecute">命令是否可以執行的方法</param>
        public RelayCommand(Action action, Func<bool> canExecute)
        {
            _execute = action;
            _canExecute = canExecute;
        }

        /// <summary>
        /// 判斷命令是否可以執行
        /// </summary>
        /// <param name="parameter"></param>
        /// <returns></returns>
        public bool CanExecute(Object parameter)
        {
            if (_canExecute == null)
                return true;
            return _canExecute();
        }

        /// <summary>
        /// 執行命令
        /// </summary>
        /// <param name="parameter"></param>
        public void Execute(Object parameter)
        {
            _execute();
        }

        /// <summary>
        /// 事件追加、移除
        /// </summary>
        public event EventHandler CanExecuteChanged
        {
            add
            {
                if (_canExecute != null)
                    CommandManager.RequerySuggested += value;
            }
            remove
            {
                if (_canExecute != null)
                    CommandManager.RequerySuggested -= value;
            }
        }

    }

創建這個類,就是為了在使用命令的時候, 創建一條命令出來用於綁定,這個類型接收兩個參數,一個是命令執行的方法,另一個是有返回值的方法, 這個返回值bool用來確定,該條命令是否可以執行,如果命令不能被執行,則按鈕的IsEnabled就被會設置成不可點擊,下面我們來挨個看下效果

MainWindowVM中創建一個命令

剛才我們已經做好了創建命令的准備工作,下面直接創建一個命令,並給這個命令指定一個方法即可。

MainWindowVM添加如下代碼:

        /// <summary>
        /// 命令要執行的方法
        /// </summary>
        void UpdateNameExecute()
        {
            EmployeeM.Name = "王明(原屬性修改)";
            EmployeeM = EmployeeM;
        }

        /// <summary>
        /// 命令是否可以執行
        /// </summary>
        /// <returns></returns>
        bool CanUpdateNameExecute()
        {
            return true;
        }

        /// <summary>
        /// 創建新命令
        /// </summary>
        public ICommand ClickAction
        {
            get
            {
                return new RelayCommand(UpdateNameExecute, CanUpdateNameExecute);
            }
        }

注意,創建這個新的命令的名字需要和我們界面按鈕Command中綁定的名字一致,叫ClickAction

這時候我們運行一下程序,點擊按鈕,可以看到命令是可以生效的。

此時我們做一個小小的改動,我們將是否可以執行的方法返回為False

        /// <summary>
        /// 命令是否可以執行
        /// </summary>
        /// <returns></returns>
        bool CanUpdateNameExecute()
        {
            return false;
        }

再次運行能夠看到,界面中按鈕已經是不可點擊的狀態了!

image-20220117151414246

所以我們綁定的這個命令是否可以執行,是直接影響到按鈕能否被點擊的!這個值會直接作用在按鈕的IsEnabled上。

命令帶點私貨-參數

上面的命令就是純命令,啥參數都沒帶上,有時候希望執行命令的時候,希望能夠傳個參數,那就需要改造一下了!

采用泛型的形式,給Action加點料,重新貼一下RelayCommand的代碼:

    public class RelayCommand<T> : ICommand
    {
        /// <summary>
        /// 命令能否執行
        /// </summary>
        readonly Func<bool> _canExecute;
        /// <summary>
        /// 命令執行的方法
        /// </summary>
        readonly Action<T> _execute;

        /// <summary>
        /// 命令的構造函數
        /// </summary>
        /// <param name="action">命令需執行的方法</param>
        /// <param name="canExecute">命令是否可以執行的方法</param>
        public RelayCommand(Action<T> action, Func<bool> canExecute)
        {
            _execute = action;
            _canExecute = canExecute;
        }

        /// <summary>
        /// 判斷命令是否可以執行
        /// </summary>
        /// <param name="parameter"></param>
        /// <returns></returns>
        public bool CanExecute(Object parameter)
        {
            if (_canExecute == null)
                return true;
            return _canExecute();
        }

        /// <summary>
        /// 執行命令
        /// </summary>
        /// <param name="parameter"></param>
        public void Execute(Object parameter)
        {
            _execute((T)parameter);
        }

        /// <summary>
        /// 事件追加、移除
        /// </summary>
        public event EventHandler CanExecuteChanged
        {
            add
            {
                if (_canExecute != null)
                    CommandManager.RequerySuggested += value;
            }
            remove
            {
                if (_canExecute != null)
                    CommandManager.RequerySuggested -= value;
            }
        }

    }

MainWindowVM(ViewModel)中創建的命令和給到的方法也要有點小變化:

        /// <summary>
        /// 命令要執行的方法
        /// </summary>
        void UpdateNameExecute(object sender)
        {
            EmployeeM.Name = "王明(原屬性修改)";
            EmployeeM = EmployeeM;
        }

        /// <summary>
        /// 命令是否可以執行
        /// </summary>
        /// <returns></returns>
        bool CanUpdateNameExecute()
        {
            return true;
        }
        /// <summary>
        /// 創建新命令
        /// </summary>
        public ICommand ClickAction
        {
            get
            {
                return new RelayCommand<object>(UpdateNameExecute, CanUpdateNameExecute);
            }
        }

參數從哪里傳呢, 當然是我們的界面傳了,通過按鈕的CommandParameter屬性來傳,這里我們將按鈕自己傳過去!

        <Button
            Grid.Row="3"
            Grid.ColumnSpan="2"
            Margin="20"
            Command="{Binding ClickAction}"
            CommandParameter="{Binding RelativeSource={RelativeSource Mode=Self}}"
            Content="更新一下信息"
            FontSize="30"
            FontWeight="Bold" />

運行斷點看一下,能夠看到按鈕自身已經當作參數傳入了:

image-20220117153354363

下一節說一下事件的綁定,讓其他事件,如MouseEnterMouseLeave也能夠像按鈕的Command一樣。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM