web-dev-qa-db-ja.com

閉じるコマンドをボタンにバインドする方法

最も簡単な方法はButtonClickイベントハンドラを実装してWindow.Close()メソッドを呼び出すことですが、Commandバインディングを使用してこれを行う方法は?

60
iLemming

現実のシナリオでは、単純なクリックハンドラは、複雑すぎるコマンドベースのシステムよりも優れていると思いますが、次のようなことができます。

この記事の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}}}"/>
48
Nir

必要なのは、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の記事 から適応)

69

実際には、C#コードがなくてもis可能です。インタラクションを使用することが重要です:

<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をウィンドウの「ウィンドウ」に追加し、次の2つの名前空間を追加します。

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

これには、Expression Blend SDK DLL=、特にMicrosoft.Expression.Interactions

Blendがない場合は、SDKをダウンロードできます here

60
theDmi

私が知っている最も簡単な解決策は、IsCancelプロパティをclose Buttonのtrueに設定することです:

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

バインディングは不要です。WPFが自動的に行います!

参照: MSDN Button.IsCancelプロパティ

40
pogosama

。NET 4.5 SystemCommands クラスの場合、トリックが行われます(.NET 4.0ユーザーはWPF Shell Extension google-Microsoft.Windows.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);
    }
3
kiran

最初は、これがどのように機能するかを理解するのに少し苦労していたので、実際に何が起こっているのかについてのより良い説明を投稿したいと思いました。

私の研究によれば、このようなことを処理する最良の方法は、コマンドバインディングを使用することです。起こるのは、プログラム内のすべてに「メッセージ」がブロードキャストされることです。したがって、あなたがしなければならないのは、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.CloseWindowCommandCloseAppおよび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">

それは実際には非常に簡単なことです。コマンドと実行する実際の関数とのリンクを設定して、コントロールにコマンドをプログラムの残りの部分に送信するように伝えます。

これは実際にこれを処理する非常に素晴らしい方法です。なぜなら、次のようなWinForms(ClickEventを使用し、イベント関数内で関数を呼び出す)のようにラッパーを持たずに、実行済み関数を再利用できるからです。

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

WPFでは、関数をコマンドにアタッチし、代わりにコマンドにアタッチされた関数を実行するようUIElementに指示します。

これで問題が解決することを願っています...

1
Andy Braham

動作することがわかった1つのオプションは、この関数を動作として設定することです。

動作:

    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プロパティをViewModelのブール「Close」プロパティにバインドします。

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イベントを発生させ、WindowであるAssociatedObject ...を閉じます。

0
Joel Palmer