设置属性时PropertyChangedEventHandler为null

发布于 2024-08-09 09:08:53 字数 1689 浏览 3 评论 0原文

<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,因此什么也没有发生。为什么事件为空,而不是当我的滑块移动时事件为空?如何解决?

<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>

Now the thing is, databinding is working correct when I am moving my slider(the model is updated when I am moving the slider).

However when a button is clicked I change the value in the model and expects it to update the view.

Code below:

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

Code in model:

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

But in OnPropertyChanged, the event is null and therefor nothing happens. Why is the event null and not when my slider is moving and how to solve it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

情何以堪。 2024-08-16 09:08:53

您不应该直接调用该事件。您所做的事情是正确的,但前提是 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 方法应该有一个继承自 EventArgs 的参数。尽管我在您的案例中考虑了正常的 PropertyChanged 事件,但 XAML 和 WPF 为另一种解释提供了空间(抱歉现在才讨论这一点)。

你(和我)在一件事上犯了错误。 引用自 MSDN 解释说:

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

您需要在重写 Volume 属性的代码中执行的操作,应该调用 PropertyChangedCallback 而是使用 OnXXX 代码作为参数 DependencyPropertyChangedEventArgs 结构。如果你问我,你当前的方法要容易得多,即使你不使用原始的 WPF 方法;-)

You should not call the event directly. What you are doing is correct, but only if the OnPropertyChanged method is implemented correctly. In the pattern recommended by Microsoft and used throughout the BCL, the OnPropertyChanged (and any OnXXXXEventName) should look as follows:

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);
    }
}

If this is correct, you shouldn't need to worry about the event being null etc. But your code shows this.OnPropertyChanged("SomeTestText"); which is not legal. The string is not a valid parameter. According to the event pattern, the OnPropertyChanged event should look as above, which means you should call it as follows:

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

Note: if the handler (event) is null, then the calling application has not been registered to the event. Through code, this can be done with somevar.PropertyChanged += handlerMethod.


Edit: about Slider / WPF and events

In a comment you suggest that it "should" go automatically. But in the code above, you call OnPropertyChanged with a string. As mentioned before, that's not legal code, because OnXXX methods should have one parameter which inherits from EventArgs. Though I considered a normal PropertyChanged event in your case, XAML and WPF gave room for another interpretation (sorry for only getting to this now).

You (and I) were mistaken about one thing. This quote from MSDN explains that:

"Note that there is an identically
named OnPropertyChanged method with a
different signature (the parameter
type is PropertyChangedEventArgs) that
can appear on a number of classes.
That OnPropertyChanged is used for
data object notifications, and is part
of the contract for
INotifyPropertyChanged."

What you need to do in the code where you override the Volume property, you should call PropertyChangedCallback instead, or use your OnXXX code with as parameter a DependencyPropertyChangedEventArgs structure. If you ask me, your current approach is way easier, even though you don't use the original WPF methods ;-)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文