INotifyPropertyChanged及其空事件

时间:2019-04-22 19:57:10

标签: c# wpf xaml

我想在WPF表单上更新名称为“ CurrentMoney”的标签; 我写了从“ INotifyPropertyChanged”实现的Money类。

UPD:我已通过创建ViewModelBase类更改为MVVM模式。 仍然具有“ PropertyChaged”空值。如何解决它以及为什么会发生?

Money.cs

    public class Money : ViewModelBase {
    private double currentMoney;

    public double CurrentMoney {
        get => currentMoney;
        set {
            currentMoney = value;
            OnPropertyChanged("CurrentMoney");
        }
    }

    public Money() => currentMoney = 10000;

    public int addMoney(double count) {
        CurrentMoney += count;
        return 1;
    }       
    public int subMoney(double count) {
        CurrentMoney -= count;
        if (currentMoney < 0)
            return 100;
        return 1;
    }
}

MainWindow.cs

public partial class MainWindow : Window {

    public Money currentMoney;

    public MainWindow ( ) {
        InitializeComponent();
        currentMoney = new Money();
        CurrentMoney.DataContext = currentMoney;
    }

    private void Initialize() {
        CurrentMoney.Content = "Current money: " + currentMoney.CurrentMoney;
        CurrentPollution.Content = CurrentPollution.Content.ToString() + Pollution.CurrentPollution;
        Facktories.Content = Facktories.Content.ToString() + FactoriesList.Quantity;
        FactoriesPollution.Content = FactoriesPollution.Content.ToString() + FactoriesList.FullPolution;
    }

    private void MenuItem_Click(object sender, RoutedEventArgs e) {
        var buy = new BuySMTH();
        this.Visibility = Visibility.Collapsed;
        buy.Show();
    }

    private void Window_ContentRendered(object sender, EventArgs e) {           
        Initialize();
    }

    private void Tmp_Click(object sender, RoutedEventArgs e) {
        currentMoney.addMoney(1000);
    }

MainWindow.xaml

<Window x:Class="Coursage.MainWindow"
    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:Coursage"
    xmlns:model="clr-namespace:Coursage.Logic.Money"
    mc:Ignorable="d"
    ContentRendered="Window_ContentRendered"
    Title="MainWindow" Height="450" Width="545.802">
<Window.Resources>
    <model:Money x:Key="Money" ></model:Money>
</Window.Resources>
<Grid DataContext="{Binding Source={StaticResource Money}}">
    <Menu Panel.ZIndex="-1" Height="25px" Width="Auto" Background="Yellow" Margin="0,0,0,398">
        <MenuItem Header="Info" Background="Green"></MenuItem>
        <MenuItem Header="Buy" Click="MenuItem_Click" Background="Red"></MenuItem>
        <MenuItem Header="Info" Background="Blue"></MenuItem>
    </Menu>
    <Label Content="{Binding Path=CurrentMoney}" Name="CurrentMoney" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10,23,0,0"/>
    <Label Content="Population: " Name="Population"  HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10,49,0,0"/>
    <Label Content="Current pollution: " Name="CurrentPollution" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10,80,0,0"/>
    <Label Content="Number of factories: " Name="Facktories" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10,235,0,0"/>
    <Label Content="Pollution of factories: " Name="FactoriesPollution" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10,261,0,0"/>
    <Label Content="Number of cars: " Name="Cars" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="250,235,0,0"/>
    <Label Content="Pollution of cars: " x:Name="CarsPollution" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="250,261,0,0"/>
    <Label Content="Start Date: " x:Name="StartDate" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="267,25,0,0"/>
    <Label Content="Day Count: " x:Name="DayCount" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="267,56,0,0"/>
    <Label Content="Date: " x:Name="Date" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="267,80,0,0"/>
    <Button Name="Tmp" Content="Button" HorizontalAlignment="Left" Margin="81,149,0,0" VerticalAlignment="Top" Width="75" Click="Tmp_Click"/>
</Grid>

3 个答案:

答案 0 :(得分:1)

您应该在属性本身上实现接口。另外,在调用PropertyChanged事件时,应使用该事件的local(scoped)句柄以避免竞争情况。

public class Money : INotifyPropertyChanged {
    double _currentMoney;

    public event PropertyChangedEventHandler PropertyChanged;
    public double CurrentMoney 
    { 
         get => _currentMoney;
         set
         {
             _currentMoney = value;
             OnPropertyChanged();
         }
    }

    public Money() => CurrentMoney = 1000;

    public int addMoney(double count) {
        CurrentMoney += count;
        return 1;
    }       

    public int subMoney(double count) {
        CurrentMoney -= count;
        if (CurrentMoney < 0) { return 100; }
        return 1;
    }

    public void OnPropertyChanged([CallerMemberName] string propertyName = null) 
    {
        var handle = PropertyChanged;
        handle?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

}

编辑:要节省一些输入,您还可以创建一个ViewModelBase类来处理较小的细节。

public abstract class ViewModelBase : INotifyPropertyChanged, IDisposable
{
    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged([CallerMemberName] string propertyName = null) 
    {
        var handle = PropertyChanged;
        handle?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    public virtual void Dispose() => PropertyChanged = null;
}

然后,在实现viewModel类时,它仅继承自base(但仍会通知属性更改)。

public class MyClass : ViewModelBase
{
    string _myField;
    public string MyProperty
    {
        get => _myField;
        set
        {
            _myField = value;
            OnPropertyChanged();
        } 
    }
}

注意:实际的错误来自[CallerMemberName]属性,并从另一个方法中调用该方法。您可以传入属性的名称作为参数,也可以将方法与属性本身一起使用,而不必指定属性名称。

答案 1 :(得分:0)

您需要传递修改后的道具名称

NotifyPropertyChanged("CurrentMoney");

答案 2 :(得分:0)

NotifyPropertyChanged采用propertyName作为参数。默认值为空。

private void NotifyPropertyChanged([CallerMemberName] string propertyName = null) {
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

如果要在ui上查看对“ propertyName”的更改,可以使用NotifyPropertyChanged(“ propertyName”)。

对于您的示例,propertyName为“ CurrentMoney”