【问题标题】:How to Bind a Command in WPF如何在 WPF 中绑定命令
【发布时间】:2012-11-30 02:31:56
【问题描述】:

有时我们多次使用复杂的方法,却忘记了完成任务的最简单方法。

我知道如何进行命令绑定,但我总是使用相同的方法。

创建一个实现 ICommand 接口的类,然后从视图模型中创建该类的新实例,绑定就像一个魅力。

这是我用于命令绑定的代码

 public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;            
        testCommand = new MeCommand(processor);
    }

    ICommand testCommand;

    public ICommand test
    {
        get { return testCommand; }
    }
    public void processor()
    {
        MessageBox.Show("hello world");
    }
}

public class MeCommand : ICommand
{
    public delegate void ExecuteMethod();
    private ExecuteMethod meth;
    public MeCommand(ExecuteMethod exec)
    {
        meth = exec;
    }

    public bool CanExecute(object parameter)
    {
        return false;
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        meth();
    }
}

但我想知道这样做的基本方法,没有第三方 dll 没有新的类创建。使用单个类执行这个简单的命令绑定。实际类从 ICommand 接口实现并完成工作。

【问题讨论】:

    标签: c# wpf icommand commandbinding


    【解决方案1】:

    Prism已经提供Microsoft.Practices.Prism.Commands.DelegateCommand

    我不确定它是否被视为第 3 方。至少它是官方的并且记录在 MSDN 上。

    一些本机内置命令,如复制、粘贴,实现了 ICommand 接口。 恕我直言,它遵循打开(用于扩展)/关闭(用于更改)原则。这样我们就可以实现自己的命令了。


    更新

    正如 WPF 命令所记录的 here,摘录...

    WPF 提供了一组预定义的命令。例如剪切、浏览返回和 向前浏览、播放、停止和暂停。

    如果命令库类中的命令不能满足您的需求, 然后您可以创建自己的命令。创建一个有两种方法 自定义命令。一是从根本上抓落实 ICommand 接口。另一种方式,更常见的方法, 是创建RoutedCommandRoutedUICommand

    我一开始就尝试了 RoutedCommand 模型,最终实现了 ICommand。

    XAML 绑定示例

    <CommandBinding Command="{x:Static custom:Window1.CustomRoutedCommand}"
                        Executed="ExecutedCustomCommand"
                        CanExecute="CanExecuteCustomCommand" />
    

    RoutedCommand 与 RoutedEvent 没有区别。这似乎是一个更好的按钮的“点击”事件处理程序。它的目的是:将应用程序逻辑与 View 分开,但需要一些附加 DependencyProperty 或代码隐藏。

    我个人觉得只实现我的 ICommand 会更舒服。

    【讨论】:

    • 它肯定被认为是第三方。我对第三方没有任何怨恨。我正在使用 GalaSoft MVVM,但我想知道简单、基本、实际的方法。无论如何,谢谢。
    • 被赞为唯一一个似乎真正读过这个问题的人。
    • @psycho 作为唯一理解我痛苦的人的建设性评论。 :-)
    • 真的检查了 DelegateCommand 吗?最小的实现看起来像this。在你的 ViewModel 类中你写 public ICommand Save { get { return new DelegateCommand(new Action&lt;object&gt;((t) =&gt; { ViewModelMethodSave(); })); } } 对我来说看起来很简单。
    • 更新了我的答案。 WPF 没有提供任何开箱即用的简单命令绑定。他们声称是通用的RoutedCommand 方法并不适合View-ViewModel 绑定。你需要可附加的依赖属性。
    【解决方案2】:

    嗯,你几乎拥有它。只要确保 CanExecute() 将返回 true,否则您的代码将不会被执行。 (我认为它实际上会,但仍然如此)。还要确保将“NotifyPropertyChanged('yourCommand')”添加到

       public ICommand test
        {
            get { return testCommand; }
            set { testCOmmand = value; NotifyPropertyChanged("test"); }
        }
    

    到这里。

    你也可以这样做 测试 = 新的 MeCOMmand(); DataContext = this;

    【讨论】:

    • 执行此命令时我要执行的方法在哪里?并且在另外一节中,您说要使用 MeCommand 类,但我不想使用我提到的任何自定义类。
    • 如前所述,命令系统由 WPF 执行,您无法更改。有RelayCommand/DelegateCommand等实现,但是如果要使用命令,就得实现ICommand接口。就那么简单。如果您想直接执行方法,也许可以开始使用事件。
    • 您投反对票只是因为您没有在问题中明确表达自己。风格不好。
    【解决方案3】:

    从你没有在VS中运行代码的情况来看,你的问题是你调用InitializeComponent(渲染XAML),然后设置DataContext而你的test属性中没有任何值,最后设置一个私有成员。 UI 应该如何注意到您的 Command 不再为空(这是它在属性中找到的最后一个值)?

    为什么不像这样懒惰地实例化命令:

    public ICommand test
    {
        get
        { 
          if(testCommand== null)
          {
             testCommand= new MeCommand(processor);
           }
          return testCommand; 
        }
    }
    

    这样它会在需要时立即出现,并且您不需要更改通知(除非您稍后在运行时更改该命令)。

    顺便说一句,在命令绑定场景中有几个地方你会感觉没有代码被执行:

    1) CanExecute() 返回 false :只需返回 true 或根据您的业务案例进行评估。

    2) CanExecute 的条件发生变化,因此它会返回 true,但不会被调用:您可以将 Command 与 CommandManager 类挂钩,请参阅here。在尝试此操作之前,请确保 1) 已解决。这可确保您的 UI 会频繁地重新查询 CanExecute,如果这还不够,请显式调用方法 CommandManager.InvalidateRequerySuggested()

    3) 您的绑定错误。像这样更改绑定代码:

    Command="{Binding Path=test, PresentationTraceSources.TraceLevel=High}"
    

    每当绑定的值被拉取或推送时,这都会向您的输出窗口发送垃圾邮件。请注意“使用最终值”一词。如果它为空,则您的命令不在它应该在的位置(还)。

    【讨论】:

    • 我的绑定没问题,没问题。我只想知道如何绑定命令而不在另一个类中实现 ICommand 然后使用该类。就我而言,它是 MeCommand。
    • CommandBinding 仅适用于 ICommand 的实现。这是 WPF 约定,没办法。可能您可能想考虑使用类似 here 的 RelayCommand。看看吧。
    • 老实说,为什么要对我们所有人投反对票?认为这对社区有帮助吗?
    【解决方案4】:

    如果您不想创建新类,请使用路由命令。这是一个小sn-p。我创建了一个路由命令作为 Save 并将其绑定到 window 的命令绑定,从 button.and 发出命令,瞧!.....我希望这可以帮助你

     public partial class Window1 : Window
     {
        public static readonly RoutedCommand Foo = new RoutedCommand();
    
        public Window1()
        {
            InitializeComponent();
        }
    
        void Foo_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            // The Window gets to determine if the Foo 
            // command can execute at this time.
            e.CanExecute = true;
        }
    
        void Foo_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            // The Window executes the command logic when the user wants to Foo.
            MessageBox.Show("The Window is Fooing...");
        }
    }
    
     <Window.CommandBindings>
     <CommandBinding
      Command="{x:Static  local:Window1.Foo}"
      CanExecute="Foo_CanExecute"
      Executed="Foo_Executed"
      />
    

    我希望我能很好地理解您的问题。

    PS:命令设计模式的需要是将执行的逻辑和命令的调用者解耦,所以Command类是一种封装逻辑的方式。

    【讨论】:

      【解决方案5】:

      我倾向于使用内置 RelayCommand 的 MVVM light 框架。

      你添加一个 ICommand 属性到你的视图模型,然后给它分配一个中继命令:-

      ICommand ClickMeCommand {get;set;}
      private void InitCommands()
      {
         ClickMeCommand = new RelayCommand(()=>HasBeenClicked=true);
         //or
         ClickMeCommand = new RelayCommand(ClickMeEvent);
      }
      public void ClickMeEvent()
      {
         HasBeenClicked=true;
      }
      

      在 xaml 中,您只需使用普通绑定:-

      <Button Content='Push me' Command='{Binding ClickMeCommand}' />
      

      【讨论】:

        【解决方案6】:

        在 WPF Window 构造函数中,要链接键盘快捷键,只需添加与委托的绑定,并将其与按键手势相关联。

        public YourWindow() //your constructor
        {
           ...
           //bind keyboard command shortcuts
           InputBindings.Add(new KeyBinding( //add a new key-binding, bind it to your command object which takes a delegate
              new WindowCommand(this)
              {
                 ExecuteDelegate = TogglePause //REPLACE TogglePause with your method delegate
              }, new KeyGesture(Key.P, ModifierKeys.Control)));
           ...
        }
        

        创建一个简单的 WindowCommand 类,该类接受一个执行委托来触发其上设置的任何方法。

        public class WindowCommand : ICommand
        {
            private MainWindow _window;
            public Action ExecuteDelegate { get; set; }
        
            public WindowCommand(MainWindow window)
            {
                _window = window;
            }
        
            public bool CanExecute(object parameter)
            {
                return true;
            }
        
            public event EventHandler CanExecuteChanged;
        
            public void Execute(object parameter)
            {
                if (ExecuteDelegate != null)
                {
                    ExecuteDelegate();
                }
                else
                {
                    throw new InvalidOperationException();
                }
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2016-05-07
          • 2015-10-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-04-25
          • 2023-01-27
          • 1970-01-01
          相关资源
          最近更新 更多