掌握iCommand Design模式

时间:2016-03-03 19:01:17

标签: c# wpf

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

这是我的情景:

一个wpf C#应用程序。 我的主窗口上有一个UserControl。 这个UserControl上有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
}

但是我如何将其与我的主窗口联系起来?

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

感谢

1 个答案:

答案 0 :(得分:2)

我的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>