【问题标题】:PropertyChangedEventHandler is null when setting property设置属性时 PropertyChangedEventHandler 为空
【发布时间】:2009-11-03 23:18:57
【问题描述】:
<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 而不是当我的滑块移动时以及如何解决?

【问题讨论】:

    标签: c# wpf inotifypropertychanged


    【解决方案1】:

    您不应该直接调用该事件。您所做的是正确的,但前提是正确实现了 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"));
    

    注意:如果处理程序(事件)为空,则调用应用程序尚未注册到事件。通过代码,这可以通过somevar.PropertyChanged += handlerMethod来完成。


    编辑:关于 Slider / WPF 和事件

    在评论中,您建议它“应该”自动运行。但是在上面的代码中,您使用字符串调用OnPropertyChanged。如前所述,这不是合法代码,因为 OnXXX 方法应该有一个继承自 EventArgs 的参数。尽管在您的情况下我考虑了一个正常的 PropertyChanged 事件,但 XAML 和 WPF 为另一种解释提供了空间(很抱歉现在才开始讨论)。

    你(和我)在一件事上搞错了。这个quote from MSDN 解释说:

    "请注意,有一个相同的 命名为 OnPropertyChanged 的​​方法 不同的签名(参数 类型是 PropertyChangedEventArgs) 可以出现在多个类中。 OnPropertyChanged 用于 数据对象通知,并且是一部分 的合同 INotifyPropertyChanged。”

    您需要在覆盖 Volume 属性的代码中执行哪些操作,您应该改为调用 PropertyChangedCallback,或使用带有 DependencyPropertyChangedEventArgs 结构的 OnXXX 代码作为参数。如果您问我,即使您不使用原始 WPF 方法,您当前的方法也更容易;-)

    【讨论】:

    • 谢谢。注册活动有效。但是,我认为 WPF 和数据绑定的聪明之处在于您不需要这样做。模型和视图都会在它们发生变化时自动变化?
    • 不一定。看看这里:msdn.microsoft.com/en-us/library/bb613543.aspx 和 esp。此文本“其他属性更改通常只与属性更改的对象有关。”,意思是:取决于(并且PropertyChanged事件属于不同类型)。
    • 感谢您提供额外信息。我想我会坚持目前的方法。现在我明白了是什么让 WPF 如此难以学习。
    猜你喜欢
    • 2012-12-25
    • 2011-04-05
    • 2012-02-15
    • 1970-01-01
    • 1970-01-01
    • 2011-04-13
    • 1970-01-01
    • 1970-01-01
    • 2012-03-10
    相关资源
    最近更新 更多