掌握 iCommand 设计模式

本文关键字:设计模式 iCommand 掌握 | 更新日期: 2023-09-27 18:37:25

尝试学习WPF,我已经阅读/测试了教程。

这是我的方案:

一个 wpf C# 应用程序。我的主窗口上有一个用户控件。此用户控件上有 4 个按钮。我的目的是将每个命令(单击)事件绑定到每个按钮。但是,我不想将每个按钮绑定到自己的类,而是将这 4 个按钮的每个命令事件绑定到 1 个类。所以。。我想将参数传递给 CanExecute 和 Execute 方法,并且我正在尝试将枚举传递给这些方法。所以。。到目前为止,我得到的是这样的:

public event EventHandler CanExecuteChanged
{
    add { CommandManager.RequerySuggested += value; }
    remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter)
{
    var commandChosen= parameter as TopMenuCommands;
    return true;
}
public void Execute(object parameter)
{
    var buttonChosen = parameter as MenuCommandObject;
    evMenuChange(buttonChosen);
}
public enum enTopMenuCommands
{
    Button1 = 0,
    Button1 = 1,
    Button1 = 2,
    Button1 = 3
}

但是我怎样才能把它绑到我的主窗口呢?

承认我可能完全错了,但我仍在学习。

谢谢

掌握 iCommand 设计模式

我的ICommand实现在构造函数中Action<object>Execute方法只是调用了Action

这样,每个命令的逻辑将从创建它的位置传入。

ICommand 实现:

public class SimpleCommand : ICommand
    {
        public event EventHandler CanExecuteChanged;
        private Action<object> _execute;
        private Func<bool> _canExecute;
        public SimpleCommand(Action<object> execute) : this(execute, null) { }
        public SimpleCommand(Action<object> execute, Func<bool> canExecute)
        {
            _execute = execute;
            _canExecute = canExecute;
        }
        public bool CanExecute(object param)
        {
            if (_canExecute != null)
            {
                return _canExecute.Invoke();
            }
            else
            {
                return true;
            }
        }
        public void Execute(object param)
        {
            _execute.Invoke(param);
        }
        protected void OnCanExecuteChanged()
        {
            CanExecuteChanged?.Invoke(this,EventArgs.Empty);
        }
        #region Common Commands
        private static SimpleCommand _notImplementedCommand;
        public static ICommand NotImplementedCommand
        {
            get
            {
                if (_notImplementedCommand == null)
                {
                    _notImplementedCommand = new SimpleCommand(o => { throw new NotImplementedException(); });
                }
                return _notImplementedCommand;
            }
        }
        #endregion
    }

使用示例:

using System;
using System.Data.Entity;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Windows.Input;
using SqlMetaQuery.Model;
using SqlMetaQuery.ViewModels.ScriptList;
using SqlMetaQuery.Windows.EditQuery;
using WpfLib;
namespace SqlMetaQuery.Windows.Main
{
    class MainWindowVm : WpfLib.ViewModel
    {
        public MainWindowVm()
        {
            if (!IsInDesignMode)
            {
                using (Context db = new Context())
                {
                    ScriptTree = new ScriptTreeVm(db.Tags
                        .Include(t => t.Scripts)
                        .OrderBy(t => t.Name));
                    CurrentUser = db.Users.Where(u => u.UserName == "Admin").AsNoTracking().FirstOrDefault();
                    MiscTag = db.Tags.Where(t => t.Name == "Misc").AsNoTracking().FirstOrDefault();
                }
            }
        }
        public ScriptTreeVm ScriptTree { get; }
        public Model.User CurrentUser { get; }
        private Model.Tag MiscTag { get; }
        private void SaveScript(Model.Script script)
        {
            using (var context = new Model.Context())
            {
                context.Scripts.Add(script);
                context.SaveChanges();
            }
        }
        #region Commands
        private ICommand _exitCommand;
        public ICommand ExitCommand
        {
            get
            {
                if (_exitCommand == null)
                {
                    _exitCommand = new SimpleCommand((arg) => WindowManager.CloseAll());
                }
                return _exitCommand;
            }
        }
        private ICommand _newScriptCommand;
        public ICommand NewScriptCommand
        {
            get
            {
                if (_newScriptCommand == null)
                {
                    _newScriptCommand = new SimpleCommand((arg) =>
                    {
                        var script = new Model.Script()
                        {
                            Title = "New Script",
                            Description = "A new script.",
                            Body = ""
                        };
                        script.Tags.Add(MiscTag);
                        var vm = new EditQueryWindowVm(script);
                        var result = WindowManager.DisplayDialogFor(vm);
                        // if (result.HasValue && result.Value)
                        //{
                        script.VersionCode = Guid.NewGuid();
                        script.CreatedBy = CurrentUser;
                        script.CreatedDate = DateTime.Now.ToUniversalTime();
                        SaveScript(script);
                        //}
                    });
                }
                return _newScriptCommand;
            }
        }

        #endregion
    }
}

XAML:

<Window x:Class="SqlMetaQuery.Windows.Main.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:controls="clr-namespace:SqlMetaQuery.Controls"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:local="clr-namespace:SqlMetaQuery.Windows.Main"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        Title="MainWindow"
        Width="800"
        Height="600"
        d:DataContext="{d:DesignInstance Type=local:MainWindowVm}"
        mc:Ignorable="d">
    <DockPanel>
        <Menu DockPanel.Dock="Top">
            <MenuItem Header="File">
                <MenuItem Command="{Binding Path=NewScriptCommand}" Header="New Script..." />
                <Separator />
                <MenuItem Command="{Binding Path=ExitCommand}" Header="Exit" />
            </MenuItem>
        </Menu>
        <Grid Margin="8">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="250" />
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <controls:ScriptTree Grid.Row="0"
                                 Grid.Column="0"
                                 DataContext="{Binding Path=ScriptTree}" />
            <GridSplitter Grid.Row="0"
                          Grid.Column="1"
                          Width="8"
                          VerticalAlignment="Stretch"
                          ResizeBehavior="PreviousAndNext" />
            <Grid Grid.Row="0" Grid.Column="2">
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="8" />
                    <RowDefinition Height="*" />
                </Grid.RowDefinitions>
                <Border Grid.Row="0" Style="{StaticResource BorderStandard}">
                    <TextBlock Text="{Binding Path=ScriptTree.CurrentScript.Title}" />
                </Border>
                <Border Grid.Row="3" Style="{StaticResource BorderStandard}">
                    <TextBlock Text="{Binding Path=ScriptTree.CurrentScript.Body}" />
                </Border>
            </Grid>
        </Grid>
    </DockPanel>
</Window>