VB のたまご

作成日: 2017/03/20, 更新日: 2017/03/20



バインドの設定

Mode

  •  データをバインドする際、どういう風に連携するかを指定できる「モード設定」があります。 モードは、「Default」、「OneTime」、「OneWay」、「OneWayToSource」、「TwoWay」の5パターンがあります。 このうち、「Default」は残りの4つのうちいづれかの適切な値となり、それはコントロールによって変わってきますのでここでは説明は省略します。

  • スポンサーリンク


  •  どういう風に動くか見てみましょう。 ここでは標準の WPF アプリケーションで作成しています。

  • Imports System.ComponentModel
    Imports System.Runtime.CompilerServices
    
    Public Class NotificationObject
        Implements INotifyPropertyChanged
    
        Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
    
        ' System.Runtime.CompilerServices 名前空間の CallerMemberName 属性を付けると、
        ' 呼び出し元のプロパティ名が自動的にセットされる(ので、呼び出し元ではいちいち文字列指定しなくてもセットしてくれるので楽)
        Protected Sub RaisePropertyChanged(<CallerMemberName> Optional propertyName As String = "")
    
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
    
        End Sub
    
    End Class
    

    Public Class Class1
        Inherits NotificationObject
    
        Private _MyName As String = "taro"
        Public Property MyName As String
            Get
                Return _MyName
            End Get
            Set(value As String)
    
                ' 変更されたかどうかを判定
                If _MyName = value Then
                    Return
                End If
    
                _MyName = value
                ' イベント発生
                Me.RaisePropertyChanged()
    
            End Set
        End Property
    
    End Class
    

    <Window x:Class="BindModeWindow1"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:w05_DataBinding4"
            mc:Ignorable="d"
            Title="BindModeWindow1" Height="300" Width="450">
     
        <StackPanel>
    
            <StackPanel Orientation="Horizontal" Margin="10">
                <TextBlock Text="OneTime" Width="110" />
                <TextBox Name="textbox1" Text="{Binding MyName, Mode=OneTime}" Width="100" />
                <Button Name="button1" Content="バインドデータの値は?" Click="button1_Click" />
                <TextBlock Name="textblock1" Text="" />
            </StackPanel>
    
            <StackPanel Orientation="Horizontal" Margin="10">
                <TextBlock Text="OneWay" Width="110" />
                <TextBox Name="textbox2" Text="{Binding MyName, Mode=OneWay}" Width="100" />
                <Button Name="button2" Content="バインドデータの値は?" Click="button2_Click" />
                <TextBlock Name="textblock2" Text="" />
            </StackPanel>
    
            <StackPanel Orientation="Horizontal" Margin="10">
                <TextBlock Text="OneWayToSource" Width="110" />
                <TextBox Name="textbox3" Text="{Binding MyName, Mode=OneWayToSource}" Width="100" />
                <Button Name="button3" Content="バインドデータの値は?" Click="button3_Click" />
                <TextBlock Name="textblock3" Text="" />
            </StackPanel>
    
            <StackPanel Orientation="Horizontal" Margin="10">
                <TextBlock Text="TwoWay" Width="110" />
                <TextBox Name="textbox4" Text="{Binding MyName, Mode=TwoWay}" Width="100" />
                <Button Name="button4" Content="バインドデータの値は?" Click="button4_Click" />
                <TextBlock Name="textblock4" Text="" />
            </StackPanel>
    
        </StackPanel>
        
    </Window>
    

    Public Class BindModeWindow1
    
        Public Sub New()
    
            ' この呼び出しはデザイナーで必要です。
            InitializeComponent()
    
            ' InitializeComponent() 呼び出しの後で初期化を追加します。
    
            ' 入力欄にデータをバインド
            Me.textbox1.DataContext = New Class1
            Me.textbox2.DataContext = New Class1
            Me.textbox3.DataContext = New Class1
            Me.textbox4.DataContext = New Class1
    
        End Sub
    
        Private Sub button1_Click(sender As Object, e As RoutedEventArgs)
    
            ' バインドデータを取得
            Dim bindData = TryCast(Me.textbox1.DataContext, Class1)
            If bindData Is Nothing Then
                Return
            End If
    
            Me.textblock1.Text = bindData.MyName
    
        End Sub
    
        Private Sub button2_Click(sender As Object, e As RoutedEventArgs)
    
            ' バインドデータを取得
            Dim bindData = TryCast(Me.textbox2.DataContext, Class1)
            If bindData Is Nothing Then
                Return
            End If
    
            Me.textblock2.Text = bindData.MyName
    
        End Sub
    
        Private Sub button3_Click(sender As Object, e As RoutedEventArgs)
    
            ' バインドデータを取得
            Dim bindData = TryCast(Me.textbox3.DataContext, Class1)
            If bindData Is Nothing Then
                Return
            End If
    
            Me.textblock3.Text = bindData.MyName
    
        End Sub
    
        Private Sub button4_Click(sender As Object, e As RoutedEventArgs)
    
            ' バインドデータを取得
            Dim bindData = TryCast(Me.textbox4.DataContext, Class1)
            If bindData Is Nothing Then
                Return
            End If
    
            Me.textblock4.Text = bindData.MyName
    
        End Sub
    
    End Class
    

  •  できたら実行してみましょう。 まずは起動時の初期状態です。「OneTime」、「OneWay」、「TwoWay」にはバインドしている MyName プロパティの値が表示されていますが、 「OneWayToSource」には何も表示されていません。

  •  この状態で各ボタンを押してみましょう。入力欄と同じ値が表示されます。

  •  次に、各入力欄の値を書き換えてみましょう。例えば taro → jiro に書き換えます。もちろん「OneWayToSource」の入力欄も書き換えます。 書き換えたら再度各ボタンを押します。すると「OneTime」、「OneWay」は書き換え前の値が、「OneWayToSource」、「TwoWay」は書き換え後の値が表示されます。

  •  「OneTime」は、画面起動時の初回のみ、バインドしたデータを表示する動作になります(Model → View)。 「OneWay」は、「OneTime」の制限無し版で、バインドしたデータの変更を受けて表示をする動作になります(Model → View)。 「OneWayToSource」は、「OneWay」の逆方向版で、入力データをバインドしたデータにセットする動作になります(View → Model)。 「TwoWay」は、相互更新で「OneWay」と「OneWayToSource」の両方を持ち合わせています。 画面データが変更されたらバインドしたデータにセットするし、バインドしたデータが変更されたら画面データを表示更新します(View ←→ Model)。

  •  例えば、TextBlock は表示専用コントロールなので、入力することはできないので、「OneTime」、または「OneWay」で問題ないはずです。 「OneWayToSource」だと表示文字列が空欄になってしまいますし、「TwoWay」は機能としては冗長です。

  •  このように機能ややりたい目的に合わせた動作を指定できるように用意されています。

  • スポンサーリンク



UpdateSourceTrigger

  •  続いて、バインドしたデータの【更新タイミング】をどうするかを設定する「UpdateSourceTrigger」があります。 画面入力した値を、バインドしたデータに反映させるタイミング(View → Model)ですね。 値は、「Default」、「LostFocus」、「PropertyChanged」、「Explicit」、の4パターンがあります。 このうち、「Default」は残りの3つのうちいづれかの適切な値となり、それはコントロールによって変わってきますのでここでは説明は省略します。

  •  どういう風に動くか見てみましょう。

  •  バインドデータは先程の Class1 を使っています。

  • <Window x:Class="UpdateSourceTriggerWindow1"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:w05_DataBinding4"
            mc:Ignorable="d"
            Title="UpdateSourceTriggerWindow1" Height="300" Width="400">
    
        <StackPanel>
    
            <StackPanel Name="stackpanel1" Orientation="Horizontal" Margin="10">
                <TextBlock Text="LostFocus" Width="110" />
                <TextBox Text="{Binding MyName, UpdateSourceTrigger=LostFocus}" Width="100" />
                <TextBox Text="フォーカス移動用" />
                <TextBlock Text="{Binding MyName}" />
            </StackPanel>
    
            <StackPanel Name="stackpanel2" Orientation="Horizontal" Margin="10">
                <TextBlock Text="PropertyChanged" Width="110" />
                <TextBox Text="{Binding MyName, UpdateSourceTrigger=PropertyChanged}" Width="100" />
                <TextBox Text="フォーカス移動用" />
                <TextBlock Text="{Binding MyName}" />
            </StackPanel>
    
            <StackPanel Name="stackpanel3" Orientation="Horizontal" Margin="10">
                <TextBlock Text="Explicit" Width="110" />
                <TextBox Name="textbox3" Text="{Binding MyName, UpdateSourceTrigger=Explicit}" Width="100" />
                <Button Content="更新の指示" Click="Button_Click" />
                <TextBlock Text="{Binding MyName}" />
            </StackPanel>
    
        </StackPanel>
        
    </Window>
    

    Public Class UpdateSourceTriggerWindow1
    
        Public Sub New()
    
            ' この呼び出しはデザイナーで必要です。
            InitializeComponent()
    
            ' InitializeComponent() 呼び出しの後で初期化を追加します。
    
            ' 入力欄にデータをバインド
            Me.stackpanel1.DataContext = New Class1
            Me.stackpanel2.DataContext = New Class1
            Me.stackpanel3.DataContext = New Class1
    
        End Sub
    
        Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
    
            ' Explicit の場合、更新タイミングは UpdateSource メソッドを呼び出したとき
            Dim be As BindingExpression = Me.textbox3.GetBindingExpression(TextBox.TextProperty)
            be.UpdateSource()
    
        End Sub
    
    End Class
    

  •  できたら実行します。初期表示では、3つそれぞれ2つとも「taro」と表示されています。 それでは、TextBox に文字を入力して値を変更してみます。「taro」の後ろに「123」でも良いですし、全部消して何かを入力してもいいです。 この時各項目の TextBlock の表示文字列の変化に注目です。

  •  「LostFocus」の場合、TextBox へ入力中は特に何も変化せず、フォーカスを移動したタイミングで TextBlock の表示文字列が更新されます。 「PropertyChanged」の場合、TextBox へ入力するたびに TextBlock の表示文字列が更新されます。 「Explicit」の場合、自動更新ではなく手動更新として、任意のタイミングで更新指示を命令することで TextBlock の表示文字列が更新されます。

  •  ちょっといいサンプルが思い浮かびませんでしたが、更新タイミングを調整することで、例えばチェックを緩めたり厳しくしたりすることができます。