2
<UserControl
    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:myapp="clr-namespace:MyPlayer.Model"
    mc:Ignorable="d"
    x:Class="MyPlayer.VolumeButtons"
    x:Name="UserControl"
    d:DesignWidth="640" d:DesignHeight="480">
    <UserControl.Resources>
        <myapp:MusicPlayerModel x:Key="Model"/>
    </UserControl.Resources>

    <Grid x:Name="LayoutRoot" DataContext="{StaticResource Model}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="35px"/>
            <ColumnDefinition Width="1.0*"/>
        </Grid.ColumnDefinitions>
        <Slider Value="{Binding Volume}" Margin="0,0,0,0" Grid.Column="1" VerticalAlignment="Center" x:Name="volumeSlider"/>
        <Button Margin="4,4,4,4" Content="Button" x:Name="muteButton" Click="MuteButton_Click"/>
    </Grid>
</UserControl>

これで問題は、スライダーを動かしているときにデータバインディングが正しく機能することです(スライダーを動かしているときにモデルが更新されます)。

ただし、ボタンをクリックすると、モデルの値が変更され、ビューが更新されることが期待されます。

以下のコード:

private void MuteButton_Click(object sender, RoutedEventArgs e)
{
     musicPlayerModel.Volume = 0;
}

モデル内のコード:

public double Volume
{
    get { return this.volume; }
    set 
    { 
         this.volume = value;
         this.OnPropertyChanged("SomeTestText");
         this.OnPropertyChanged("Volume");
    }
}

しかし、OnPropertyChanged では、イベントは null であるため、何も起こりません。スライダーが動いているときではなく、イベントが null になるのはなぜですか? また、その解決方法を教えてください。

4

1 に答える 1

3

イベントを直接呼び出さないでください。あなたがしていることは正しいですが、OnPropertyChanged メソッドが正しく実装されている場合のみです。Microsoft が推奨し、BCL 全体で使用されているパターンでは、OnPropertyChanged (および任意の OnXXXXEventName) は次のようになります。

protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{
    // get handler (usually a local event variable or just the event)
    if (this.PropertyChanged != null)
    {
        this.PropertyChanged(this, e);
    }
}

これが正しければ、イベントが null であることなどを心配する必要はありthis.OnPropertyChanged("SomeTestText");ません。文字列は有効なパラメーターではありません。イベント パターンによると、OnPropertyChanged イベントは上記のようになります。つまり、次のように呼び出す必要があります。

this.OnPropertyChanged(new PropertyChangedEventArgs("Volume"));

注: ハンドラー (イベント) が null の場合、呼び出し元のアプリケーションはイベントに登録されていません。コードを通じて、これは で行うことができますsomevar.PropertyChanged += handlerMethod


編集:Slider / WPFとイベントについて

コメントでは、自動的に「すべき」であると提案しています。しかし、上記のコードではOnPropertyChanged、文字列で呼び出しています。前述のように、これは正当なコードではありません。OnXXX メソッドには から継承する 1 つのパラメータが必要だからEventArgsです。あなたのケースでは通常の PropertyChanged イベントを考えましたが、XAML と WPF は別の解釈の余地を与えました (今しか理解できなくて申し訳ありません)。

あなた (と私) は 1 つの点で間違っていました。MSDN からのこの引用は、次のことを説明しています。

「多くのクラスに表示される可能性がある、異なる署名 (パラメーターの型は PropertyChangedEventArgs) を持つ同じ名前の OnPropertyChanged メソッドがあることに注意してください。その OnPropertyChanged はデータ オブジェクト通知に使用され、INotifyPropertyChanged の契約の一部です。」

Volume プロパティをオーバーライドするコードで行う必要があることは、代わりに呼び出すか、 DependencyPropertyChangedEventArgs構造体PropertyChangedCallbackをパラメータとして OnXXX コードを使用する必要があります。あなたが私に尋ねると、元のWPFメソッドを使用していなくても、現在のアプローチはずっと簡単です;-)

于 2009-11-03T23:47:27.840 に答える