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

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

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

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


на самом деле, это is возможно без кода 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"

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

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


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

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

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

ссылки: кнопка MSDN.IsCancel property.


для .NET 4.5 SystemCommands класс сделает трюк (пользователи .NET 4.0 могут использовать расширение оболочки WPF google-Microsoft.Окна.Shell или 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}"/>

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

    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, если знаете, что команда должна всегда быть выполнена, Save может быть хорошим примером в зависимости от приложения. Вот пример:

<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 и закрывает AssociatedObject... это окно.