Question

Je suis intéressé par la création de commandes qui sont disponibles partout dans mon application WPF.

Je les aime travailler de la même manière que Cut, Copy, Paste et les autres commandes de niveau d'application, par exemple:

<Button Command="Paste" />

Je suppose que je pouvais CommandBindings de configuration pour l'instance d'application, mais cette propriété ne sont pas disponibles.

Comment cela se fait?

Le mieux que j'ai réussi à ce jour est de créer une suite de commandes sur la fenêtre de niveau supérieur et d'y accéder puis comme ça ...:

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

Ce qui fonctionne, mais il est bien entendu étroitement couplé, et donc extrêmement fragiles.

Était-ce utile?

La solution

Vous pouvez CommandBindings de configuration pour "All Windows" de votre application WPF et mettre en œuvre des gestionnaires de commandes dans la classe d'application.

Tout d'abord, créer une classe de conteneur de commande statique. Par exemple,

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

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

Ensuite, réglez votre commande personnalisée à Button.Command comme celui-ci.

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

Enfin, mettre en œuvre le gestionnaire de commande de votre commande personnalisée dans la classe d'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;
        }
    }
}

Autres conseils

membres StackOverflow m'a aidé tant de fois que je décide maintenant de contribuer et partager; -)

Sur la base de la réponse de Shou Takenaka, voici ma mise en œuvre.

Mon intérêt était de produire que un fichier réutilisable .


Tout d'abord, créer une classe de conteneur commande (s)

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

Ensuite, déclarer une ressource 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>

Enfin, lier une propriété de commande à la propriété de votre ressource d'application:

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

c'est tous les gens: -)

Je n'ai pas aimé la complexité des autres solutions, mais après quelques heures de recherche j'ai découvert qu'il est très simple.

La première installation de votre commande comme vous le faites habituellement, mais ajouter une propriété statique pour WPF afin qu'il puisse obtenir une instance de votre commande.

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

Ajoutez une référence à l'espace de noms de votre commande dans votre XAML (dernière ligne), comme ceci:

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

Ensuite, il suffit de référence de votre propriété statique dans votre XAML comme ceci:

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

Si vous essayez de définir CommandBindings ou InputBindings comme ressources dans votre App.xaml, vous constaterez que vous ne pouvez pas les utiliser, parce que XAML ne vous permet pas d'utiliser soit:

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

ou à des liaisons de commande Set avec un dispositif de réglage de style:

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

car aucune de ces propriétés ont un accesseur « set ». En utilisant l'idée ce poste, je suis venu avec une façon propre d'utiliser les ressources de App.xaml ou tout autre dictionnaire de ressources.

D'abord, vous définissez vos liaisons de commande et les liaisons d'entrée indirectement, comme vous le feriez pour tout autre ressource:

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

et puis vous faites référence à eux de la XAML d'une autre classe:

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

Le CollectionSetterBehavior est un comportement réutilisable qui ne « ensemble » la propriété à la valeur de, mais efface la place de la collecte, et re-Remplit il. Ainsi, la collection ne change pas, seul le contenu est tout.

Voici la source du comportement:

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 vous n'êtes pas familier avec les comportements, ajoutez d'abord cet espace de noms:

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

et ajoutez la référence correspondant à votre projet.

Déclarez le CommandBinding au niveau Application d'où il peut être réutilisé partout.

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

Dans votre fichier App.xaml.cs, définir des gestionnaires correspondant:

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

Utilisation

Dans un fichier XAML, l'utiliser comme ci-dessous:

 <RichTextBox x:Name="Rtb1" ContextMenuOpening="Rtb1_ContextMenuOpening_1" FontSize="15" Margin="10,10,10,-73">            
        <RichTextBox.CommandBindings>
            <StaticResourceExtension ResourceKey="PasteCommandKey"/>
        </RichTextBox.CommandBindings>
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top