Как привязать команду закрыть к кнопке


самый простой способ-это реализовать ButtonClick обработчик событий и вызов Window.Close() метод, но как это сделать через Command привязка?

7 55

7 ответов:

Я думаю, что в реальных сценариях простой обработчик кликов, вероятно, лучше, чем сверхсложные командные системы, но вы можете сделать что-то вроде этого:

используя RelayCommand из этой статьи 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}}}"/>

все, что требуется, это немного 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>

и немного C#...

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

(взято из этой статье)

на самом деле, это и возможно без кода C#. ключ должен использовать взаимодействия:

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

для того чтобы это работало, надо просто установить x:Name вашего окна в "окно", и добавьте эти два пространства имен:

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

это требует, чтобы вы добавили выражение Blend SDK DLL в свой проект, в частности Microsoft.Expression.Interactions.

в случае, если у вас нет Blend, SDK можно загрузить здесь.

самое простое решение, которое я знаю, - это установить IsCancel свойство true для закрытия Button:

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

никаких привязок не требуется, WPF сделает это за вас автоматически!

ссылки: кнопка MSDN.Свойство IsCancel.

для .NET 4.5 SystemCommands класс будет делать трюк (.Net версии 4.0 пользователи могут использовать WPF расширение оболочки Google - компания Microsoft.Окна.Шелл или Николас решение).

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

в коде позади вы можете реализовать обработчики следующим образом:

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

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

в начале у меня также было немного проблем с выяснением того, как это работает, поэтому я хотел опубликовать лучшее объяснение того, что на самом деле происходит.

согласно моим исследованиям, лучший способ справиться с такими вещами-использовать привязки команд. То, что происходит, - это "сообщение", транслируемое на все в программе. Так что вам нужно сделать, это использовать CommandBinding. Что это по существу делает, так это говорит:"Когда вы слышите это сообщение, сделайте это".

так, в Вопрос пользователь пытается закрыть окно. Первое, что нам нужно сделать, это настроить наши функции, которые будут вызываться, когда SystemCommand.CloseWindowCommand трансляции. При необходимости можно назначить функцию, которая определяет, следует ли выполнять команду. Примером может быть закрытие формы и проверка, если пользователь сохранил.

MainWindow.код XAML.CS (или другой код)

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

теперь нам нужно настроить "соединение" между SystemCommands.CloseWindowCommand и CloseApp и CloseAppCanExecute

MainWindow.xaml (или все, что реализует CommandBindings)

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

вы можете опустить CanExecute, если вы знаете, что команда должна быть в состоянии всегда выполняться сохранить может быть хорошим примером в зависимости от приложения. Вот пример:

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

наконец, вам нужно сказать UIElement, чтобы отправить CloseWindowCommand.

<Button Command="SystemCommands.CloseWindowCommand">

на самом деле, очень простая вещь, чтобы сделать, просто установить связь между Команда и фактическая функция для выполнения затем скажите элементу управления, чтобы отправить команду остальной части вашей программы, сказав: "Хорошо, все запускают свои функции для команды CloseWindowCommand".

это на самом деле очень хороший способ передать это, потому что вы можете повторно использовать выполненную функцию на всем протяжении, не имея оболочки, как вы бы сказали WinForms (используя ClickEvent и вызывая функцию в функции события), например:

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

в WPF вы прикрепляете функция к команде и скажите UIElement выполнить функцию, прикрепленную к команде вместо этого.

Я надеюсь, что это проясняет ситуацию...

один вариант, который я нашел, чтобы работать, чтобы установить эту функцию в поведении.

Поведение:

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

в окне XAML вы устанавливаете ссылку на него и привязываете свойство Close поведения к логическому свойству "Close" на вашем ViewModel:

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

Итак, из представления назначьте ICommand для изменения свойства Close на ViewModel, которое привязано к свойству Close поведения. Когда PropertyChanged событие запускается поведение запускает событие OnCloseTriggerChanged и закрывает Связанный объект... это и есть окно.