web-dev-qa-db-fra.com

Comment lier la commande Fermer à un bouton

Le moyen le plus simple consiste à implémenter le gestionnaire d'événements ButtonClick et à invoquer la méthode Window.Close(), mais comment le faire via une liaison Command?

60
iLemming

Je pense que dans des scénarios du monde réel, un simple gestionnaire de clics est probablement meilleur que les systèmes basés sur des commandes trop compliqués, mais vous pouvez faire quelque chose comme ça:

en utilisant RelayCommand de cet article http://msdn.Microsoft.com/en-us/magazine/dd419663.aspx

public class MyCommands
{
    public static readonly ICommand CloseCommand =
        new RelayCommand( o => ((Window)o).Close() );
}
<Button Content="Close Window"
        Command="{X:Static local:MyCommands.CloseCommand}"
        CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, 
                           AncestorType={x:Type Window}}}"/>
48
Nir

Il suffit d'un peu de XAML ...

<Window x:Class="WCSamples.Window1"
        xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml">
    <Window.CommandBindings>
        <CommandBinding Command="ApplicationCommands.Close"
                        Executed="CloseCommandHandler"/>
    </Window.CommandBindings>
    <StackPanel Name="MainStackPanel">
        <Button Command="ApplicationCommands.Close" 
                Content="Close Window" />
    </StackPanel>
</Window>

Et un peu de C # ...

private void CloseCommandHandler(object sender, ExecutedRoutedEventArgs e)
{
    this.Close();
}

(adapté de cet article MSDN )

69
Nicholas Armstrong

En fait, c'est c'est possible sans code C #. La clé est d'utiliser les interactions:

<Button Content="Close">
  <i:Interaction.Triggers>
    <i:EventTrigger EventName="Click">
      <ei:CallMethodAction TargetObject="{Binding ElementName=window}" MethodName="Close"/>
    </i:EventTrigger>
  </i:Interaction.Triggers>
</Button>

Pour que cela fonctionne, définissez simplement le x:Name de votre fenêtre à "fenêtre", et ajoutez ces deux espaces de noms:

xmlns:i="http://schemas.Microsoft.com/expression/2010/interactivity" 
xmlns:ei="http://schemas.Microsoft.com/expression/2010/interactions"

Cela nécessite que vous ajoutiez le SDK Expression Blend DLL à votre projet, en particulier Microsoft.Expression.Interactions.

Si vous n'avez pas Blend, le SDK peut être téléchargé ici .

60
theDmi

La solution la plus simple que je connaisse est de définir la propriété IsCancel sur true de la fermeture Button:

<Button Content="Close" IsCancel="True" />

Aucune liaison nécessaire, WPF le fera automatiquement pour vous!

Référence: propriété MSDN Button.IsCancel .

40
pogosama

Pour .NET 4.5 SystemCommands , la classe fera l'affaire (les utilisateurs de .NET 4.0 peuvent utiliser l'extension WPF Shell google - Microsoft.Windows.Shell ou Nicholas Solution).

    <Window.CommandBindings>
        <CommandBinding Command="{x:Static SystemCommands.CloseWindowCommand}" 
                        CanExecute="CloseWindow_CanExec" 
                        Executed="CloseWindow_Exec" />
    </Window.CommandBindings>
    <!-- Binding Close Command to the button control -->
    <Button ToolTip="Close Window" Content="Close" Command="{x:Static SystemCommands.CloseWindowCommand}"/>

Dans le code derrière, vous pouvez implémenter les gestionnaires comme ceci:

    private void CloseWindow_CanExec(object sender, CanExecuteRoutedEventArgs e)
    {
        e.CanExecute = true;
    }

    private void CloseWindow_Exec(object sender, ExecutedRoutedEventArgs e)
    {
        SystemCommands.CloseWindow(this);
    }
3
kiran

Au début, j'avais aussi un peu de mal à comprendre comment cela fonctionnait, donc je voulais publier une meilleure explication de ce qui se passe réellement.

D'après mes recherches, la meilleure façon de gérer des choses comme celle-ci est d'utiliser les liaisons de commandes. Ce qui se passe est un "Message" est diffusé à tout dans le programme. Donc, ce que vous devez faire, c'est utiliser le CommandBinding. Ce que cela signifie essentiellement, c'est "Quand vous entendez ce Message, faites ceci".

Ainsi, dans la question, l'utilisateur tente de fermer la fenêtre. La première chose que nous devons faire est de configurer nos fonctions qui seront appelées lorsque le SystemCommand.CloseWindowCommand est diffusé. Vous pouvez éventuellement affecter une fonction qui détermine si la commande doit être exécutée. Un exemple serait de fermer un formulaire et de vérifier si l'utilisateur a enregistré.

MainWindow.xaml.cs (ou autre code-derrière)

void CloseApp( object target, ExecutedRoutedEventArgs e ) {
    /*** Code to check for State before Closing ***/
    this.Close();
}

void CloseAppCanExecute( object sender, CanExecuteRoutedEventArgs e ) {
    /*** Logic to Determine if it is safe to Close the Window ***/
    e.CanExecute = true;
}

Maintenant, nous devons configurer la "connexion" entre le SystemCommands.CloseWindowCommand et les CloseApp et CloseAppCanExecute

MainWindow.xaml (ou tout ce qui implémente CommandBindings)

<Window.CommandBindings>
    <CommandBinding Command="SystemCommands.CloseWindowCommand"
                    Executed="CloseApp"
                    CanExecute="CloseAppCanExecute"/>
</Window.CommandBindings>

Vous pouvez omettre CanExecute si vous savez que la commande doit toujours pouvoir être exécutée. Save peut être un bon exemple selon l'application. Voici un exemple:

<Window.CommandBindings>
    <CommandBinding Command="SystemCommands.CloseWindowCommand"
                    Executed="CloseApp"/>
</Window.CommandBindings>

Enfin, vous devez dire à UIElement d'envoyer le CloseWindowCommand.

<Button Command="SystemCommands.CloseWindowCommand">

C'est en fait une chose très simple à faire, il suffit de configurer le lien entre la commande et la fonction réelle à exécuter, puis de dire au contrôle d'envoyer la commande au reste de votre programme en disant "Ok tout le monde exécute vos fonctions pour la commande CloseWindowCommand".

C'est en fait une très belle façon de gérer cela, car vous pouvez réutiliser la fonction exécutée partout sans avoir un wrapper comme vous le feriez avec, par exemple, WinForms (en utilisant un ClickEvent et en appelant une fonction dans la fonction d'événement) comme:

protected override void OnClick(EventArgs e){
    /*** Function to Execute ***/
}

Dans WPF, vous attachez la fonction à une commande et dites à l'UIElement d'exécuter la fonction attachée à la commande à la place.

J'espère que cela clarifie les choses ...

1
Andy Braham

Une option que j'ai trouvée efficace consiste à définir cette fonction comme un comportement.

Le comportement:

    public class WindowCloseBehavior : Behavior<Window>
{
    public bool Close
    {
        get { return (bool) GetValue(CloseTriggerProperty); }
        set { SetValue(CloseTriggerProperty, value); }
    }

    public static readonly DependencyProperty CloseTriggerProperty =
        DependencyProperty.Register("Close", typeof(bool), typeof(WindowCloseBehavior),
            new PropertyMetadata(false, OnCloseTriggerChanged));

    private static void OnCloseTriggerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var behavior = d as WindowCloseBehavior;

        if (behavior != null)
        {
            behavior.OnCloseTriggerChanged();
        }
    }

    private void OnCloseTriggerChanged()
    {
        // when closetrigger is true, close the window
        if (this.Close)
        {
            this.AssociatedObject.Close();
        }
    }
}

Dans la fenêtre XAML, vous y définissez une référence et liez la propriété Close du comportement à une propriété booléenne "Close" sur votre ViewModel:

xmlns:i="http://schemas.Microsoft.com/expression/2010/interactivity"
<i:Interaction.Behaviors>
    <behavior:WindowCloseBehavior Close="{Binding Close}" />
</i:Interaction.Behaviors>

Ainsi, à partir de la vue, affectez un ICommand pour modifier la propriété Close sur le ViewModel qui est lié à la propriété Close du comportement. Lorsque l'événement PropertyChanged est déclenché, le comportement déclenche l'événement OnCloseTriggerChanged et ferme l'AssociatedObject ... qui est la fenêtre.

0
Joel Palmer