2011-01-17 6 views
15

Estoy interesado en crear comandos que estén disponibles desde cualquier lugar en mi aplicación WPF.Comandos de WPF, ¿cómo declarar los comandos de nivel de aplicación?

me gustaría que les permite trabajar de la misma manera como Cut, Copy, Paste y los otros comandos de nivel de aplicación, es decir:

<Button Command="Paste" /> 

I asumido que pude CommandBindings de configuración para la instancia de solicitud, pero que la propiedad no está disponible.

¿Cómo se hace esto?

El mejor que he conseguido hasta ahora es crear un conjunto de comandos en la ventana de nivel superior y luego acceder a ellos de esta manera ...:

<Button Command="{x:Static namespace::MainWindow.CommandName}" /> 

que funciona, pero es, por supuesto, fuertemente acoplado, y tan extremadamente frágil.

Respuesta

31

Puede configurar CommandBindings para "Todas las ventanas" de su aplicación WPF e implementar controladores de comando en la clase de aplicación.

Antes que nada, cree una clase de contenedor de comandos estáticos. Por ejemplo,

namespace WpfApplication1 
{ 
    public static class MyCommands 
    { 
     private static readonly RoutedUICommand doSomethingCommand = new RoutedUICommand("description", "DoSomethingCommand", typeof(MyCommands)); 

     public static RoutedUICommand DoSomethingCommand 
     { 
      get 
      { 
       return doSomethingCommand; 
      } 
     } 
    } 
} 

A continuación, configure su comando personalizado en Button.Command así.

<Window x:Class="WpfApplication1.MainWindow" 
     ... 
     xmlns:local="clr-namespace:WpfApplication1"> 
    <Grid> 
     ... 
     <Button Command="local:MyCommands.DoSomethingCommand">Execute</Button> 
    </Grid> 
</Window> 

Finalmente, implemente el controlador de comando de su comando personalizado en la clase de Aplicación.

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; 
     } 
    } 
} 
+0

Gracias Shou, me Intentaré esto. Supongo que puedo usar nuevos nombres de comando, p. Ej. 'ApplicationCommands.MyCommand'?Si no, esto no responde mi pregunta. – ocodo

+0

También puede usar comandos personalizados. –

+0

Cambie el ejemplo para usar un comando personalizado, no Pegar. No puedo encontrar ninguna otra referencia para agregar nuevos comandos a 'ApplicationCommands', ¿puedes proporcionar un enlace? - Además, ¿mostrarías el uso de XAML, especialmente si difiere de '

2

Si intenta definir CommandBindings o InputBindings como recursos en su App.xaml, se encuentra que no se puede utilizar, porque XAML no permite que usted utilice, ya sea:

<Window ... CommandBindings="{StaticResource commandBindings}"> 

oa establecer enlaces de comando con un conjunto de estilos:

<Setter Property="CommandBindings" Value="{StaticResource commandBindings}"> 

porque ninguna de estas propiedades tiene un descriptor de acceso "establecido". Al usar la idea en this post, se me ocurrió una forma clara de usar los recursos del App.xaml o cualquier otro diccionario de recursos.

En primer lugar, definir sus ataduras de mando y enlaces de entrada indirectamente, al igual que lo haría con cualquier otro recurso:

<InputBindingCollection x:Key="inputBindings"> 
     <KeyBinding Command="Help" Key="H" Modifiers="Ctrl"/> 
    </InputBindingCollection> 
    <CommandBindingCollection x:Key="commandBindings"> 
     <CommandBinding Command="Help" Executed="CommandBinding_Executed"/> 
    </CommandBindingCollection> 

y luego se refieren a los mismos desde el XAML de otra clase:

<Window ...> 
    <i:Interaction.Behaviors> 
     <local:CollectionSetterBehavior Property="InputBindings" Value="{StaticResource inputBindings}"/> 
     <local:CollectionSetterBehavior Property="CommandBindings" Value="{StaticResource commandBindings}"/> 
    </i:Interaction.Behaviors> 
    ... 
</Window> 

El CollectionSetterBehavior es un comportamiento reutilizable que no "establece" la propiedad a su valor, sino que borra la colección y vuelve a llenarla. Entonces, la colección no cambia, solo sus contenidos.

Aquí está la fuente de la conducta:

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); 
    } 
} 

Si no está familiarizado con las conductas, primero Añadir este espacio de nombres:

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 

y añadir la referencia correspondiente a su proyecto.

+0

Muestra cómo utilizaría estos comandos en XAML, p. Ej. '

6

miembros StackOverflow me ayudaron a tantos vez que decido ahora a contribuir y compartir ;-)

Sobre la base de la respuesta de Shou Takenaka, aquí está mi aplicación.

Mi interés era producir solo un archivo reutilizable.


En primer lugar, crear una clase de comando (s) de contenedores

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; 
     } 
    } 
} 

A continuación, declarar un recurso en 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> 

Por último, se unen cualquier propiedad de comando a la propiedad de su recurso de aplicación:

<Button Content="Click to execute my command" 
     Command="{Binding Source={StaticResource sh}, Path=MyCommand}" 
     CommandParameter="{Binding ElementName=myElement}" /> 

eso es todo amigos :-)

2

que no me gusta la complejidad de las otras soluciones, pero después de unas horas de investigación descubrí que es muy simple.

Primero configure su comando como lo hace normalmente, pero agregue una propiedad estática para WPF para que pueda obtener una instancia de su comando.

class MyCommand : ICommand 
{ 
    // Singleton for the simple cases, may be replaced with your own factory if needed. 
    static MyCommand() 
    { 
     Instance = new MyCommand(); 
    } 
    public static ICommand Instance { get; private set; } 

    public bool CanExecute(object parameter) 
    { 
     return true; // TODO: Implement 
    } 

    public event EventHandler CanExecuteChanged; 

    public void Execute(object parameter) 
    { 
     // TODO: Implement  
    } 
} 

Agregue una referencia al espacio de nombres de su comando en el XAML (última línea), así:

<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">  

A continuación, sólo hacer referencia a su propiedad estática de su XAML como esto:

<Button Content="Button" Command="commands:MyCommand.Instance" /> 
2

Declare el CommandBinding en el nivel Application desde donde se puede reutilizar en todas partes.

<Application.Resources>  
    <CommandBinding x:Key="PasteCommandKey" Command="ApplicationCommands.Paste" CanExecute="CommandBinding_CanExecute_1"/> 
</Application.Resources> 

En el archivo App.xaml.cs, definir manipuladores correspondientes:

private void CommandBinding_CanExecute_11(object sender, System.Windows.Input.CanExecuteRoutedEventArgs e) 
    { 
     e.CanExecute = false; 
    } 

uso

En cualquier archivo XAML, usarlo como a continuación:

<RichTextBox x:Name="Rtb1" ContextMenuOpening="Rtb1_ContextMenuOpening_1" FontSize="15" Margin="10,10,10,-73">    
     <RichTextBox.CommandBindings> 
      <StaticResourceExtension ResourceKey="PasteCommandKey"/> 
     </RichTextBox.CommandBindings> 
+1

Dadas las explicaciones y la calidad de las respuestas ya publicadas. Tu respuesta no está realmente agregando valor. Por favor, evite publicar el código sin explicación. Recomiendo editar su respuesta para explicar primero, y mostrar el código en segundo lugar. Gracias. – ocodo

+0

Esta respuesta muy específica me ayudó mucho. Nadie más dijo que es posible poner '' dentro de ''. @ocodo tu comentario no es válido. – Endrju

+0

@Endrju - mire las fechas y edite el historial antes de comentar – ocodo

Cuestiones relacionadas