我有兴趣创建可在我的WPF应用程序中的任何位置使用的命令。
我希望它们的工作方式与Cut
,Copy
,Paste
以及其他应用程序级命令相同,即:
<Button Command="Paste" />
我假设我可以为Application实例设置CommandBindings,但该属性不可用。
这是怎么做到的?
到目前为止我管理的最好的是在顶级窗口创建一套命令,然后像这样访问它们......:
<Button Command="{x:Static namespace::MainWindow.CommandName}" />
哪个有效,但当然紧密耦合,非常脆弱。
答案 0 :(得分:34)
您可以为WPF应用程序的“所有Windows”设置CommandBindings,并在Application类中实现命令处理程序。
首先,创建一个静态命令容器类。例如,
namespace WpfApplication1
{
public static class MyCommands
{
private static readonly RoutedUICommand doSomethingCommand = new RoutedUICommand("description", "DoSomethingCommand", typeof(MyCommands));
public static RoutedUICommand DoSomethingCommand
{
get
{
return doSomethingCommand;
}
}
}
}
接下来,将自定义命令设置为Button.Command,如下所示。
<Window x:Class="WpfApplication1.MainWindow"
...
xmlns:local="clr-namespace:WpfApplication1">
<Grid>
...
<Button Command="local:MyCommands.DoSomethingCommand">Execute</Button>
</Grid>
</Window>
最后,在Application类中实现自定义命令的命令处理程序。
namespace WpfApplication1
{
public partial class App : Application
{
public App()
{
var binding = new CommandBinding(MyCommands.DoSomethingCommand, DoSomething, CanDoSomething);
// Register CommandBinding for all windows.
CommandManager.RegisterClassCommandBinding(typeof(Window), binding);
}
private void DoSomething(object sender, ExecutedRoutedEventArgs e)
{
...
}
private void CanDoSomething(object sender, CanExecuteRoutedEventArgs e)
{
...
e.CanExecute = true;
}
}
}
答案 1 :(得分:5)
StackOverflow成员帮助我这么多时间,我现在决定贡献和分享; - )
根据Shou Takenaka的回答,这是我的实施。
我的兴趣是只生成一个可重复使用的文件。
首先,创建一个命令容器类
namespace Helpers
{
public class SpecificHelper
{
private static RoutedUICommand _myCommand = new RoutedUICommand("myCmd","myCmd", typeof(SpecificHelper));
public static RoutedUICommand MyCommand { get { return _myCommand; } }
static SpecificHelper()
{
// Register CommandBinding for all windows.
CommandManager.RegisterClassCommandBinding(typeof(Window), new CommandBinding(MyCommand, MyCommand_Executed, MyCommand_CanExecute));
}
// TODO: replace UIElement type by type of parameter's binded object
#region MyCommand
internal static void MyCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
if (!verifType<UIElement>(e.Parameter)) return;
e.Handled = true;
// TODO : complete the execution code ...
}
internal static void SelectAll_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
if (!verifType<UIElement>(e.Parameter)) return;
e.CanExecute = true;
var item = (e.Parameter as UIElement);
// TODO : complete the execution code ...
}
#endregion
private static bool verifType<T>(object o)
{
if (o == null) return false;
if (!o.GetType().Equals(typeof(T))) return false;
return true;
}
}
}
接下来,在App.xaml中声明一个资源:
<Application x:Class="Helper.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:h="clr-namespace:Helpers"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
StartupUri="MainWindow.xaml" >
<Application.Resources>
<h:SpecificHelper x:Key="sh" />
</Application.Resources>
</Application>
最后,将任何命令属性绑定到应用程序资源的属性:
<Button Content="Click to execute my command"
Command="{Binding Source={StaticResource sh}, Path=MyCommand}"
CommandParameter="{Binding ElementName=myElement}" />
这是所有人: - )
答案 2 :(得分:4)
我不喜欢其他解决方案的复杂性,但经过几个小时的研究后我发现它非常简单。
首先像往常一样设置命令,但为WPF添加一个静态属性,以便它可以获取命令的实例。
class MyCommand : ICommand
{
// Singleton for the simple cases, may be replaced with your own factory
public static ICommand Instance { get; } = new MyCommand();
public bool CanExecute(object parameter)
{
return true; // TODO: Implement
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
// TODO: Implement
}
}
在XAML(最后一行)中添加对命令命名空间的引用,如下所示:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:commands="clr-namespace:MyProject.Commands">
然后在你的XAML中引用你的静态属性,如下所示:
<Button Content="Button" Command="commands:MyCommand.Instance" />
答案 3 :(得分:1)
如果您尝试将CommandBindings
或InputBindings
定义为App.xaml
中的资源,您会发现无法使用它们,因为XAML不允许您使用其中任何一种:< / p>
<Window ... CommandBindings="{StaticResource commandBindings}">
或使用样式设置器设置命令绑定:
<Setter Property="CommandBindings" Value="{StaticResource commandBindings}">
因为这些属性都没有“set”访问器。使用this post中的想法,我想出了一种使用来自App.xaml
或任何其他资源字典的资源的简洁方法。
首先,您可以间接定义命令绑定和输入绑定,就像您使用任何其他资源一样:
<InputBindingCollection x:Key="inputBindings">
<KeyBinding Command="Help" Key="H" Modifiers="Ctrl"/>
</InputBindingCollection>
<CommandBindingCollection x:Key="commandBindings">
<CommandBinding Command="Help" Executed="CommandBinding_Executed"/>
</CommandBindingCollection>
然后从另一个类的XAML中引用它们:
<Window ...>
<i:Interaction.Behaviors>
<local:CollectionSetterBehavior Property="InputBindings" Value="{StaticResource inputBindings}"/>
<local:CollectionSetterBehavior Property="CommandBindings" Value="{StaticResource commandBindings}"/>
</i:Interaction.Behaviors>
...
</Window>
CollectionSetterBehavior
是一种可重用的行为,它不会将属性“设置”为它的值,而是清除集合并重新填充它。所以集合不会改变,只有它的内容。
以下是行为的来源:
public class CollectionSetterBehavior : Behavior<FrameworkElement>
{
public string Property
{
get { return (string)GetValue(PropertyProperty); }
set { SetValue(PropertyProperty, value); }
}
public static readonly DependencyProperty PropertyProperty =
DependencyProperty.Register("Property", typeof(string), typeof(CollectionSetterBehavior), new UIPropertyMetadata(null));
public IList Value
{
get { return (IList)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(IList), typeof(CollectionSetterBehavior), new UIPropertyMetadata(null));
protected override void OnAttached()
{
var propertyInfo = AssociatedObject.GetType().GetProperty(Property);
var property = propertyInfo.GetGetMethod().Invoke(AssociatedObject, null) as IList;
property.Clear();
foreach (var item in Value) property.Add(item);
}
}
如果您不熟悉行为,请先添加此命名空间:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
并为项目添加相应的引用。
答案 4 :(得分:1)
在CommandBinding
级别声明Application
可以在任何地方重复使用的地方。
<Application.Resources>
<CommandBinding x:Key="PasteCommandKey" Command="ApplicationCommands.Paste" CanExecute="CommandBinding_CanExecute_1"/>
</Application.Resources>
在App.xaml.cs
文件中,定义相应的处理程序:
private void CommandBinding_CanExecute_11(object sender, System.Windows.Input.CanExecuteRoutedEventArgs e)
{
e.CanExecute = false;
}
<强>用法
在任何xaml文件中,使用如下所示:
<RichTextBox x:Name="Rtb1" ContextMenuOpening="Rtb1_ContextMenuOpening_1" FontSize="15" Margin="10,10,10,-73">
<RichTextBox.CommandBindings>
<StaticResourceExtension ResourceKey="PasteCommandKey"/>
</RichTextBox.CommandBindings>