如何在WPF中绑定命令
有时我们使用复杂的方法很多次,我们忘记了完成任务的最简单方法。
我知道如何进行命令绑定,但我总是使用相同的方法。
创建一个实现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接口实现并完成工作。
Prism已经提供了Microsoft.Practices.Prism.Commands.DelegateCommand
我不确定它是否被视为第三方。 至少它是官方的,并在MSDN上记录。
一些本机内置命令如copy,paste实现ICommand接口。 恕我直言,它遵循开放(扩展)/关闭(改变)原则。 这样我们就可以实现自己的命令。
更新
正如WPF Commanding 在此记录 ,摘录……
WPF提供了一组预定义命令。 如Cut,BrowseBack和BrowseForward,Play,Stop和Pause。
如果命令库类中的命令不满足您的需要,则可以创建自己的命令。 有两种方法可以创建自定义命令。 第一个是从头开始实现ICommand接口。 另一种方式, 更常见的方法是创建RoutedCommand或RoutedUICommand 。
我在开始时尝试过RoutedCommand模型,最后实现了ICommand。
示例XAML绑定
RoutedCommand与RoutedEvent没有什么不同。 这似乎是一个更好的按钮的’Clicked’事件处理程序。 它的目的是:将应用程序逻辑与View分开但需要一些附加DependencyProperty或代码隐藏。
我个人觉得只需要实现我的ICommand就更舒服了。
我倾向于使用内置RelayCommand的MVVM灯架。
您将ICommand属性添加到视图模型,然后为其分配一个relay命令: –
ICommand ClickMeCommand {get;set;} private void InitCommands() { ClickMeCommand = new RelayCommand(()=>HasBeenClicked=true); //or ClickMeCommand = new RelayCommand(ClickMeEvent); } public void ClickMeEvent() { HasBeenClicked=true; }
在xaml中你只需使用普通绑定: –
如果您不想创建新类,请使用routed命令。 这是一个小片段。 我已经创建了一个路由命令作为Save并将其绑定到命令绑定窗口,从button提起命令。瞧!我希望这可以帮助你
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..."); } }
我希望我能理解你的问题。
PS:命令设计模式的需要是分离执行逻辑和命令调用程序.So Command类是一种封装逻辑的方法。
如果不在VS中运行代码来判断,你的问题是你调用InitializeComponent
(渲染XAML),然后设置DataContext
而不在test
属性中有任何值,最后设置一个私有成员。 UI如何注意到您的Command不再为null(这是它在Property中找到的最后一个值)?
为什么不像这样懒洋洋地实现命令:
public ICommand test { get { if(testCommand== null) { testCommand= new MeCommand(processor); } return testCommand; } }
这样它就会在需要时立即存在,并且您不需要更改通知(除非您稍后在运行时更改该命令)。
顺便说一下,在命令绑定场景中,您可以感觉到没有代码正在执行的几个位置:
1)CanExecute()返回false:只返回true或根据您的业务案例进行评估。
2)CanExecute的条件发生变化,因此它将返回true,但不会被调用:您可以使用CommandManager类挂起Command,请参见此处 。 在尝试之前确保1)已解决。 这可以确保您的UI会经常重新查询CanExecute
,如果仍然不够,请显式调用Method CommandManager.InvalidateRequerySuggested()
。
3)你的绑定是错误的。 像这样更改绑定代码:
Command="{Binding Path=test, PresentationTraceSources.TraceLevel=High}"
只要拉动或推动绑定的值,这将垃圾邮件输出窗口。 注意“使用最终值”这个术语。 如果它为null,则命令不是它应该的位置(还)。
好吧,你几乎拥有它。 只需确保CanExecute()将返回true,否则您的代码将不会被执行。 (我认为它实际上会,但仍然)。 还要确保将“NotifyPropertyChanged(’yourCommand’)”添加到
public ICommand test { get { return testCommand; } set { testCOmmand = value; NotifyPropertyChanged("test"); } }
到这里。
你也可以做test = new MeCOmmand(); DataContext = this;
在WPF窗口构造函数中,要链接键盘快捷键,只需使用委托添加绑定,并将其与键手势相关联。
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(); } } }