none
CommandParameter に複数の要素を指定する方法について RRS feed

  • 質問

  • WPF でアプリケーションを作っています。

    Window に TextBox1、TextBox2、Button を配置し、Button をクリックすると、Button の CommandParameter として TextBox1、TextBox2 の Text プロパティを指定したいと考えています。

    TextBox1 だけなら、以下の記述でできます。

            <Button Content="Button" Height="28" HorizontalAlignment="Left" Margin="542,338,0,0"
                    Name="button3" VerticalAlignment="Top" Width="153"
                    Command="{Binding Source={StaticResource myCommand}}"
                    CommandParameter="{Binding ElementName=textBox1, Path=Text}">
            </Button>

    ただ、2 つ以上の要素を指定したい場合の記述が分かりません。ご教授いただけないでしょうか。よろしくお願いいたします。

    2015年2月24日 7:18

回答

  • こんにちは。

    マルチバインディングしてコンバータの中で配列化してやれば良いのではないでしょうか。

    MainWindow.xaml

    <Window x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="350" Width="525">
        <Window.DataContext>
            <local:MainWindowViewModel />
        </Window.DataContext>
        <Window.Resources>
            <local:MultiText x:Key="hogeConv" />
        </Window.Resources>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
            </Grid.RowDefinitions>
            <TextBox Grid.Row="0" Name="txt1" Text="AAA" />
            <TextBox Grid.Row="1" Name="txt2" Text="BBB" />
            <Button Grid.Row="2" Content="Button" Command="{Binding Command}">
                <Button.CommandParameter>
                    <MultiBinding Converter="{StaticResource hogeConv}">
                        <MultiBinding.Bindings>
                            <Binding ElementName="txt1" Path="Text" />
                            <Binding ElementName="txt2" Path="Text" />
                        </MultiBinding.Bindings>
                    </MultiBinding>
                </Button.CommandParameter>
            </Button>
        </Grid>
    </Window>

    MultiText.vb

    Imports System.Windows.Data
    
    Public Class MultiText
        Implements IMultiValueConverter
    
        Public Function Convert(values() As Object, targetType As Type, parameter As Object, culture As Globalization.CultureInfo) As Object Implements IMultiValueConverter.Convert
            Dim a As String() = New String() {values(0).ToString, values(1).ToString}
            Return a
        End Function
    
        Public Function ConvertBack(value As Object, targetTypes() As Type, parameter As Object, culture As Globalization.CultureInfo) As Object() Implements IMultiValueConverter.ConvertBack
            Throw New NotImplementedException()
        End Function
    End Class

    ※エラー考慮など一切してないです。Stringであればもっと簡単にできるのかな・・・



    2015年2月24日 7:32
    モデレータ
  • こんにちは

    MainWindowにMainWindowViewModelを作るなら、単純に最初からバインドしとけばどうでしょうか。
    これなら、ViewModelのプロパティを参照するだけなので、ややこしくCommandParameterで処理しなくていい気もします。

    <TextBox Grid.Row="0" Name="txt1" Text="{Binding TextA}" />
    <TextBox Grid.Row="1" Name="txt2" Text="{Binding TextB}" />
    • 回答としてマーク t-yumi 2015年2月24日 8:24
    2015年2月24日 8:01
  • CommandParameterに独自に作成したクラスを提供する方法もあります。私は汎用的なパラメータークラスを作成し、それを使用することが多いです。以下を参考にしてみて下さい。

    CommandParameter に独自クラスを指定するとデータバインディングできない?
    https://social.msdn.microsoft.com/Forums/ja-JP/3f039685-9f63-4111-91e5-a38ee8e35456/commandparameter-?forum=wpfja

    #ただ、inoguchiさんも書かれてますが、通常はそれぞれのTextBoxのTextプロパティをバインドし、コマンドを実行する側で(コードビハインドとかViewModel)で、それを参照する方が素直ですね。


    ★良い回答には回答済みマークを付けよう! MVP - .NET  http://d.hatena.ne.jp/trapemiya/

    • 回答としてマーク t-yumi 2015年2月24日 8:24
    2015年2月24日 8:06
    モデレータ

すべての返信

  • こんにちは。

    マルチバインディングしてコンバータの中で配列化してやれば良いのではないでしょうか。

    MainWindow.xaml

    <Window x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="350" Width="525">
        <Window.DataContext>
            <local:MainWindowViewModel />
        </Window.DataContext>
        <Window.Resources>
            <local:MultiText x:Key="hogeConv" />
        </Window.Resources>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
            </Grid.RowDefinitions>
            <TextBox Grid.Row="0" Name="txt1" Text="AAA" />
            <TextBox Grid.Row="1" Name="txt2" Text="BBB" />
            <Button Grid.Row="2" Content="Button" Command="{Binding Command}">
                <Button.CommandParameter>
                    <MultiBinding Converter="{StaticResource hogeConv}">
                        <MultiBinding.Bindings>
                            <Binding ElementName="txt1" Path="Text" />
                            <Binding ElementName="txt2" Path="Text" />
                        </MultiBinding.Bindings>
                    </MultiBinding>
                </Button.CommandParameter>
            </Button>
        </Grid>
    </Window>

    MultiText.vb

    Imports System.Windows.Data
    
    Public Class MultiText
        Implements IMultiValueConverter
    
        Public Function Convert(values() As Object, targetType As Type, parameter As Object, culture As Globalization.CultureInfo) As Object Implements IMultiValueConverter.Convert
            Dim a As String() = New String() {values(0).ToString, values(1).ToString}
            Return a
        End Function
    
        Public Function ConvertBack(value As Object, targetTypes() As Type, parameter As Object, culture As Globalization.CultureInfo) As Object() Implements IMultiValueConverter.ConvertBack
            Throw New NotImplementedException()
        End Function
    End Class

    ※エラー考慮など一切してないです。Stringであればもっと簡単にできるのかな・・・



    2015年2月24日 7:32
    モデレータ
  • Tak1wa さん、早速のご回答ありがとうございます。

    ご教示いただいた内容をアプリケーションに実装し、こちらでも期待通りの結果となりました。

    とても勉強になりました。ありがとうございます!


    • 編集済み t-yumi 2015年2月24日 8:00 誤字
    2015年2月24日 8:00
  • こんにちは

    MainWindowにMainWindowViewModelを作るなら、単純に最初からバインドしとけばどうでしょうか。
    これなら、ViewModelのプロパティを参照するだけなので、ややこしくCommandParameterで処理しなくていい気もします。

    <TextBox Grid.Row="0" Name="txt1" Text="{Binding TextA}" />
    <TextBox Grid.Row="1" Name="txt2" Text="{Binding TextB}" />
    • 回答としてマーク t-yumi 2015年2月24日 8:24
    2015年2月24日 8:01
  • CommandParameterに独自に作成したクラスを提供する方法もあります。私は汎用的なパラメータークラスを作成し、それを使用することが多いです。以下を参考にしてみて下さい。

    CommandParameter に独自クラスを指定するとデータバインディングできない?
    https://social.msdn.microsoft.com/Forums/ja-JP/3f039685-9f63-4111-91e5-a38ee8e35456/commandparameter-?forum=wpfja

    #ただ、inoguchiさんも書かれてますが、通常はそれぞれのTextBoxのTextプロパティをバインドし、コマンドを実行する側で(コードビハインドとかViewModel)で、それを参照する方が素直ですね。


    ★良い回答には回答済みマークを付けよう! MVP - .NET  http://d.hatena.ne.jp/trapemiya/

    • 回答としてマーク t-yumi 2015年2月24日 8:24
    2015年2月24日 8:06
    モデレータ
  • inoguchi さん、trapemiya さん、追加情報をありがとうございます。

    まだ WPF の経験が浅く、試行錯誤しながら MVVM でコーディングしているところです。

    inoguchi さん、trapemiya さんの回答を見て、確かに CommandParameter で処理しなくとも私のやりたいことは実現できることに気づきました。ご指摘いただき、誠にありがとうございました。

    2015年2月24日 8:26