2016年12月18日日曜日

VB WPF お勉強 12 TextBox 値と Button 有効化との連動

WPF では やはり 勝手が違います。
例えば、 TextBox の値と連動して Button 有効・無効 を操作しよう と思うと、
Form の頃とは違い、 少し、面倒な事をしなければ いけません。
画面設計 と言うか xaml のコードで書かないと ... 。


Form の頃は、TextBox 値と Button 有効化との連動させるのに、イベントハンドラを書いていました。
こんな感じですね。

    ' System.Windows.Forms
    Private Sub TextBox1_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged
        Me.Button1.Enabled = IIf(Me.TextBox1.Text = "", False, True)
    End Sub

でも、この考え方をそのまま WPF に持ち込むと上手くは動いてくれません。
参照出来ない! と怒られてしまいます。


結局、 xaml に Trigger と Setter を書いて対処します。
TextBox1 の値が "" の時、Button1 を 無効化 する例です。

        <Button x:Name="button1" Content="Button1" HorizontalAlignment="Right" Margin="0,0,30,30" VerticalAlignment="Bottom"
                Width="75" Height="23">

            <Button.Style>
                <Style TargetType="Button">
                    <Setter Property="IsEnabled" Value="True" />
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding Text, ElementName=TextBox1}" Value="">
                           <Setter Property="IsEnabled" Value="False" />
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </Button.Style>
        </Button>

では、 ふたつの TextBox と連動するには ... 。
ふたつ ですから AND と OR が考えられますね。

OR では。
そう、 何れかの TextBox の値が "" の時、Button2 を 無効化 する例です。
            <Button x:Name="button1" Content="Button1" HorizontalAlignment="Right" Margin="0,0,30,30" VerticalAlignment="Bottom"
                    Width="75" Height="23">
                <Button.Style>
                    <Style TargetType="Button">
                        <Setter Property="IsEnabled" Value="True" />
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding Text, ElementName=TextBox2}" Value="">
                                <Setter Property="IsEnabled" Value="False" />
                            </DataTrigger>
                            <DataTrigger Binding="{Binding Text, ElementName=TextBox2_Copy}" Value="">
                                <Setter Property="IsEnabled" Value="False" />
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </Button.Style>
            </Button>

AND では。
そう、 ふたつ共 TextBox の値が "" の時 のみ、Button3 を 無効化 する例です。
        <Button x:Name="button1" Content="Button1" HorizontalAlignment="Right" Margin="0,0,30,30" VerticalAlignment="Bottom"
                Width="75" Height="23">


            <Button.Style>
                <Style TargetType="Button">
                    <Setter Property="IsEnabled" Value="True" />
                    <Style.Triggers>
                        <MultiDataTrigger>
                            <MultiDataTrigger.Conditions>
                                <Condition Binding="{Binding Text, ElementName=TextBox3}" Value=""/>
                                <Condition Binding="{Binding Text, ElementName=TextBox3_Copy}" Value=""/>
                            </MultiDataTrigger.Conditions>
                            <Setter Property="IsEnabled" Value="False" />
                        </MultiDataTrigger>
                    </Style.Triggers>
                </Style>             </Button.Style>
        </Button>


では、 実行時の画面から。
全て初期値を持たせた TextBox で 中央の下段をふたつ共に空白に変えた時 です。
あっ、 上の xaml Code では座標値が 皆同じまま なので、 調整しています ... 。
 .



中央の Button2 は 条件が OR ですから 無効化、 右の Buton3 は AND なので 有効のまま、 です。



尚、 xaml ではなく Code で Trigger と Setter を書く事も可能の様ですが、 一般的では無い様で ... 。
特に今回の様に、Binding が絡む場合、 私のレベルでは 手に負えません!。.  でも、頑張って見ました。.
更に、 行数も多いので、 普通は、素直に、 xaml に集約が 正解と思います。


一応、 code-behind で対応する例を 載せて置きます。  VB.net 。
   上の最初の例を 普通の Button を対象にする場合。  Loaded Event Handler から呼び出します。.

    Private Sub SetTriggerForButton()
        '<Button.Style>
        '   <Style TargetType="Button">
        '      <Setter Property="IsEnabled" Value="True" />
        '         <Style.Triggers>
        '             <DataTrigger Binding="{Binding Text, ElementName=TextBox1}" Value="">
        '                 <Setter Property="IsEnabled" Value="False" />
        '             </DataTrigger>
        '         </Style.Triggers>
        '    </Style>
        '</Button.Style>

        'Me.Button1.Triggers : Readonly

        Dim button1Style As New Style
        button1Style.TargetType = Me.Button1.GetType

        Dim button1Binding As New Binding("Text")
        button1Binding.ElementName = "TextBox1"

        Dim button1Trigger As New DataTrigger
        button1Trigger.Binding = button1Binding
        button1Trigger.Value = ""
        button1Trigger.Setters.Add(New Setter(Button.IsEnabledProperty, False))

        button1Style.Triggers.Add(button1Trigger)

        Me.Button1.Style = button1Style
    End Sub


あ~、 疲れたぁ ... 。  何かの時に役に立つかなぁ ... 。.



[2016/12/18] 冒頭に Header 追加。 追記の区切り 挿入。

0 件のコメント:

コメントを投稿