C# 如何在 WPF 中绑定命令
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13838884/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to Bind a Command in WPF
提问by MegaMind
Sometimes we used complex ways so many times, we forgot the simplest ways to do the task.
有时,我们多次使用复杂的方法,却忘记了完成任务的最简单方法。
I know how to do command binding, but i always use same approach.
我知道如何进行命令绑定,但我总是使用相同的方法。
Create a class that implements ICommand interface and from the view model i create new instance of that class and binding works like a charm.
创建一个实现 ICommand 接口的类,并从视图模型中创建该类的新实例,绑定就像一个魅力。
This is the code that i used for command binding
这是我用于命令绑定的代码
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();
}
}
But i want to know the basic way to do this, no third party dll no new class creation. Do this simple command binding using a single class. Actual class implements from ICommand interface and do the work.
但我想知道这样做的基本方法,没有第三方 dll 没有新的类创建。使用单个类执行这个简单的命令绑定。实际类从 ICommand 接口实现并完成工作。
采纳答案by aifarfa
Prismalready provided Microsoft.Practices.Prism.Commands.DelegateCommand
Prism已经提供了Microsoft.Practices.Prism.Commands.DelegateCommand
I'm not sure is it considered as 3rd party. At least it's official and documented on MSDN.
我不确定它是否被视为第 3 方。至少它是官方的并记录在 MSDN 上。
Some native build-in commands such copy, paste implements ICommand interface. IMHO it following the Open(for extends)/Close(for changes) principle. so that we can implement our own command.
一些本机内置命令如复制、粘贴实现 ICommand 接口。恕我直言,它遵循打开(用于扩展)/关闭(用于更改)原则。这样我们就可以实现我们自己的命令。
Update
更新
As WPF Commanding documented here, an excerpt...
正如此处记录的 WPF 命令,摘录...
WPF provides a set of predefined commands. such as Cut, BrowseBack and BrowseForward, Play, Stop, and Pause.
If the commands in the command library classes do not meet your needs, then you can create your own commands. There are two ways to create a custom command. The first is to start from the ground up and implement the ICommand interface. The other way, and the more common approach, is to create a RoutedCommandor a RoutedUICommand.
WPF 提供了一组预定义的命令。例如剪切、浏览后退和浏览前进、播放、停止和暂停。
如果命令库类中的命令不能满足您的需求,那么您可以创建自己的命令。有两种方法可以创建自定义命令。首先是从头开始并实现 ICommand 接口。另一种更常见的方法是创建RoutedCommand或RoutedUICommand。
I've tried RoutedCommand model at the beginning and ended up with implementing ICommand.
我在开始时尝试过 RoutedCommand 模型,最终实现了 ICommand。
sample XAML binding
示例 XAML 绑定
<CommandBinding Command="{x:Static custom:Window1.CustomRoutedCommand}"
Executed="ExecutedCustomCommand"
CanExecute="CanExecuteCustomCommand" />
RoutedCommand is not different from RoutedEvent. this seems like a better button's 'Clicked' event handler. It serves the purpose: To separate app logic from View but require some attach DependencyProperty or code-behind.
RoutedCommand 与 RoutedEvent 没有区别。这似乎是一个更好的按钮的 'Clicked' 事件处理程序。它的目的是:将应用程序逻辑与视图分开,但需要一些附加 DependencyProperty 或代码隐藏。
personally I feel more comfortable with just implement my ICommand.
就我个人而言,我对实施我的 ICommand 感到更自在。
回答by Erti-Chris Eelmaa
Well, you almost have it. Just make sure that CanExecute() will return true, otherwise your code won't be executed. (I think it actually will, but still). Also make sure that add "NotifyPropertyChanged('yourCommand')" to
好吧,你几乎拥有它。只要确保 CanExecute() 将返回 true,否则您的代码将不会被执行。(我认为它实际上会,但仍然如此)。还要确保将“NotifyPropertyChanged('yourCommand')”添加到
public ICommand test
{
get { return testCommand; }
set { testCOmmand = value; NotifyPropertyChanged("test"); }
}
to here.
到这里。
You can alternatively do test = new MeCOmmand(); DataContext = this;
你也可以做 test = new MeCOMmand(); 数据上下文 = 这个;
回答by Sebastian Edelmeier
Judging from what you do without running the Code in VS, your problem is that you call InitializeComponent(render XAML), then set the DataContextwithout any value being in your testProperty and finally set a private member. How is the UI supposed to notice that your Command is not null anymore (which was the last value it found in the Property)?
从你没有在 VS 中运行代码的情况来看,你的问题是你调用InitializeComponent(渲染 XAML),然后DataContext在你的test属性中设置没有任何值,最后设置一个私有成员。UI 应该如何注意到您的 Command 不再为空(这是它在属性中找到的最后一个值)?
Why not instanciate the Command lazily like so :
为什么不像这样懒惰地实例化命令:
public ICommand test
{
get
{
if(testCommand== null)
{
testCommand= new MeCommand(processor);
}
return testCommand;
}
}
That way it will be there as soon as it's required and you don't need Change notification (unless you change that command later at runtime).
这样它就会在需要时立即出现并且您不需要更改通知(除非您稍后在运行时更改该命令)。
By the way, there's a few spots where you get the feeling no code is being executed in the Command Binding scenario :
顺便说一下,有几个地方你会觉得在命令绑定场景中没有代码被执行:
1) CanExecute() returns false : just return true or evaluate according to your business case.
1) CanExecute() 返回 false :只返回 true 或根据您的业务案例进行评估。
2) The conditions of CanExecute change, so that it would return true, but it doesn't get called: You can hook your Command up with the CommandManager class, see here. Make sure 1) is solved before you try this. This ensures that your UI will requery the CanExecutepretty frequently, and if that is still not enough, call the Method CommandManager.InvalidateRequerySuggested()explicitly.
2) CanExecute 的条件发生变化,因此它会返回 true,但不会被调用:您可以将您的 Command 与 CommandManager 类挂钩,请参见此处。在尝试此操作之前,请确保 1) 已解决。这确保您的 UI 将CanExecute非常频繁地重新查询,如果这还不够,请CommandManager.InvalidateRequerySuggested()显式调用该方法。
3) Your Binding is wrong. Change the binding code like so:
3)你的绑定是错误的。像这样更改绑定代码:
Command="{Binding Path=test, PresentationTraceSources.TraceLevel=High}"
This will spam your output window whenever the value of the binding is pulled or pushed. Look out for the term "using final value". If it's null, your Command isn't where it's supposed to be (yet).
每当拉动或推送绑定的值时,这都会向您的输出窗口发送垃圾邮件。注意术语“使用最终值”。如果它为空,则您的 Command 不在它应该在的位置(还)。
回答by Paritosh
Please use routed command in case of you don't want to create new class. here is a small snippet. I have created a routed command as Save and bind it to command binding of window , raise the command from button.and voila!..... I hope this may help you
如果您不想创建新类,请使用 routed 命令。这是一个小片段。我创建了一个路由命令作为 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"
/>
I hope I understood your problem well.
我希望我能很好地理解你的问题。
PS: The need of command design pattern is to decouple the logic of execution and invoker of command.So Command class is a way to encapsulate the logic.
PS:命令设计模式的需要是解耦命令的执行逻辑和调用者,所以Command类是一种封装逻辑的方式。
回答by Ross Dargan
I tend to use the MVVM light framework which comes with a RelayCommand built in.
我倾向于使用内置 RelayCommand 的 MVVM 轻型框架。
You add an ICommand property to your view model, then assign a relaycommand to it:-
您将 ICommand 属性添加到您的视图模型,然后为其分配一个中继命令:-
ICommand ClickMeCommand {get;set;}
private void InitCommands()
{
ClickMeCommand = new RelayCommand(()=>HasBeenClicked=true);
//or
ClickMeCommand = new RelayCommand(ClickMeEvent);
}
public void ClickMeEvent()
{
HasBeenClicked=true;
}
In the xaml you just use normal binding:-
在 xaml 中,您只需使用普通绑定:-
<Button Content='Push me' Command='{Binding ClickMeCommand}' />
回答by Ayo I
In the WPF Window constructor, to link a keyboard shortcut, simply add a binding with a delegate, and associate it with a key gesture.
在 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)));
...
}
Create a simple WindowCommand class which takes an execution delegate to fire off any method set on it.
创建一个简单的 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();
}
}
}

