none
MainWindow直下のコントロールとプロパティーに対してTwoWayバインディングを設定する方法 RRS feed

  • 質問

  • 開発環境はVS2010+Windows7です。
    MainWindowにはSlider1が配置されており、MainWindowクラスの「SliderValue」プロパティーに連動してスライダーが動くようにしたいです。またスライダーを動かすとMainWindowクラスの「SliderValue」プロパティーも連動して変化させたいです。

    「SliderValue」プロパティーはMainWindowクラス外からも操作されるため、Publicとしています。

    Sub Button1_Clickをテストボタンとしていますが、「SliderValue」プロパティーに値を代入するとMainWindowのコントロールが消えて「4」という文字だけが表示されてしまいます。

    このコードのどこに問題があるのか、教えていただきたいです。


    <XAML>
    <Window x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
        <Grid>
            <Slider Height="28" HorizontalAlignment="Left" Margin="78,66,0,0" Name="Slider1" VerticalAlignment="Top" Width="297" />
            <Button Content="Button" Height="40" HorizontalAlignment="Left" Margin="74,163,0,0" Name="Button1" VerticalAlignment="Top" Width="176" />
        </Grid>
    </Window>


    <VB.net>
    Class MainWindow

        Public Property SliderValue As String
            Get
                Return CType(GetValue(ContentProperty), String)
            End Get
            Set(value As String)
                SetValue(ContentProperty, value)
                Debug.Print(value) '←スライダーを動かす度にこの行が実行されて欲しい
            End Set

        End Property

        Public Shared ReadOnly SliderValueProperty As DependencyProperty = DependencyProperty.Register("SliderValue", GetType(String), GetType(MainWindow))


        Private Sub MainWindow_Loaded(sender As Object, e As System.Windows.RoutedEventArgs) Handles Me.Loaded
            Dim binding1 As New Binding("SliderValue") With {.Source = Me, .Mode = BindingMode.TwoWay}
            Me.Slider1.SetBinding(System.Windows.Controls.Slider.ValueProperty, binding1)

        End Sub

        Private Sub Button1_Click(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles Button1.Click
            Me.SliderValue = 4 '←コントロールが消えて「4」という文字が表示されてしまう
        End Sub

    End Class
    2017年9月18日 4:00

回答

  • SliderのValueプロパティはDoubleなのでStringやSingleよりもDoubleのほうがよけいな変換が発生しないので適切ではありますが、原因はそこではありません。

    SliderValueプロパティのget,setでContentPropertyに対してGetValue,SetValueしていることが間違いです。
    提示されているコードだとWindowのContentプロパティに対してSetValueしてしまっているために、Windowの直下であるContentが書き換わってしまっています。
    (WindowはContentControlを継承しているので直下にはContentが表示されます。提示されているXAMLではGirdがContentプロパティに設定されます。)

    ただしくは新たに追加しているSliderValuePropertyに対してGetValue,SetValueします。

    Public Property SliderValue As String
    	Get
    		Return CType(GetValue(SliderValueProperty), String)
    	End Get
    	Set(value As String)
    		SetValue(SliderValueProperty, value)
    		Debug.Print(value) '←スライダーを動かす度にこの行が実行されて欲しい
    	End Set
    End Property
    

    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 回答としてマーク huahi11112 2017年9月18日 5:38
    2017年9月18日 4:53
  • 質問後に思い付いたのですが、TwoWayバインディングにしなくてもSlider.ValueChangedイベントを利用し、PropertyのGet 及びSetで処理すれば良いとも思いました。

    多くの場合、INotifyPropertyChangedインターフェースが使用されます。

    (参考)
    INotifyPropertyChangedを実装しておこう
    http://vb.netde業務アプリ.com/142.htm

    上記の例とは違いますが、もちろん、MainWindowにINotifyPropertyChangedインターフェースを直接実装してもかまいません。今回のケースではそうするのが簡単だと思います。


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

    2017年9月19日 10:13
    モデレータ

すべての返信

  • Public Property SliderValue String  ←ここが間違いだと思いSingleに変えてみましたが動かないのは同じでした。
    2017年9月18日 4:03
  • SliderのValueプロパティはDoubleなのでStringやSingleよりもDoubleのほうがよけいな変換が発生しないので適切ではありますが、原因はそこではありません。

    SliderValueプロパティのget,setでContentPropertyに対してGetValue,SetValueしていることが間違いです。
    提示されているコードだとWindowのContentプロパティに対してSetValueしてしまっているために、Windowの直下であるContentが書き換わってしまっています。
    (WindowはContentControlを継承しているので直下にはContentが表示されます。提示されているXAMLではGirdがContentプロパティに設定されます。)

    ただしくは新たに追加しているSliderValuePropertyに対してGetValue,SetValueします。

    Public Property SliderValue As String
    	Get
    		Return CType(GetValue(SliderValueProperty), String)
    	End Get
    	Set(value As String)
    		SetValue(SliderValueProperty, value)
    		Debug.Print(value) '←スライダーを動かす度にこの行が実行されて欲しい
    	End Set
    End Property
    

    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 回答としてマーク huahi11112 2017年9月18日 5:38
    2017年9月18日 4:53
  • Return CType(GetValue(SliderValueProperty), String)↑ここでSliderValuePropertyを使うんですね!

    質問後に思い付いたのですが、TwoWayバインディングにしなくてもSlider.ValueChangedイベントを利用し、PropertyのGet 及びSetで処理すれば良いとも思いました。

    とても分かり易く参考になる御回答をいただき、ありがとうございました。


    2017年9月18日 5:45
  • 質問後に思い付いたのですが、TwoWayバインディングにしなくてもSlider.ValueChangedイベントを利用し、PropertyのGet 及びSetで処理すれば良いとも思いました。

    多くの場合、INotifyPropertyChangedインターフェースが使用されます。

    (参考)
    INotifyPropertyChangedを実装しておこう
    http://vb.netde業務アプリ.com/142.htm

    上記の例とは違いますが、もちろん、MainWindowにINotifyPropertyChangedインターフェースを直接実装してもかまいません。今回のケースではそうするのが簡単だと思います。


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

    2017年9月19日 10:13
    モデレータ
  • >多くの場合、INotifyPropertyChangedインターフェースが使用されます。

    これは魅力的なソリューションですね。今後こういうことをする機会がまた来ると思いますので、これを実装してみたいと思います。

    Trapemiyaさん、今回も御回答ありがとうございました。

    2017年9月21日 8:03