C# 如果不创建绑定对象的新实例,OnPropertyChange不会更新绑定

C# 如果不创建绑定对象的新实例,OnPropertyChange不会更新绑定,c#,wpf,data-binding,C#,Wpf,Data Binding,我在WPF中的数据绑定方面遇到了一些问题,所以我一直在尝试弄清楚到底发生了什么。但是我遇到了一些我不明白的事情,我希望有人能给我解释一下。下面的代码不是我试图使用的任何东西,它只是用于测试 我有一个简单的类“Lamp”,只有一个字符串属性“Name”。我还重写ToString(),以便它返回名称 在“ViewModel”类中,我创建了一个“Lamp”属性和一个ICommand: class ViewModel : ViewModelBase { private Lamp _lam

我在WPF中的数据绑定方面遇到了一些问题,所以我一直在尝试弄清楚到底发生了什么。但是我遇到了一些我不明白的事情,我希望有人能给我解释一下。下面的代码不是我试图使用的任何东西,它只是用于测试

我有一个简单的类“Lamp”,只有一个字符串属性“Name”。我还重写ToString(),以便它返回名称

在“ViewModel”类中,我创建了一个“Lamp”属性和一个ICommand:

class ViewModel : ViewModelBase
{
        private Lamp _lamp1;

        public Lamp Lamp1
        {
            get { return _lamp1; }
            set { _lamp1 = value; }// OnPropertyChanged("Lamp1"); }
        }

        public ICommand Lamp_click { get { return new RelayCommand(param => LampClickExecute(param)); } }


        public ViewModel()
        {
            Lamp1 = new Lamp() { Name = "Test" };
        }

        private void LampClickExecute(object param)
        {
            var name = Lamp1.Name + "I";

            //HERE IS THE QUESTION!
            //Lamp1 = new Lamp() { Name = name };
            Lamp1.Name = name;

            OnPropertyChanged("Lamp1");
        }
}
在视图中,我只有一个绑定到命令的按钮和一个绑定到Lamp1的标签:

        <Button x:Name="btn_lamp" Content="Button" HorizontalAlignment="Left" Margin="859,27,0,0" VerticalAlignment="Top" Height="29" Command="{Binding Path= Lamp_click}" CommandParameter="{Binding Path=Lamp1 }"/>
        <Label Content= "{Binding Lamp1}" HorizontalAlignment="Left" Margin="797,56,0,0" VerticalAlignment="Top"/>

您应该使用INotifyPropertyChanged并将代码添加到ViewModelBase类中,以更新视图上的任何对象

{
    public class ViewModelBase: INotifyPropertyChanged
    {
        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
        {
            var changed = PropertyChanged;
            if (changed == null)
                return;

            changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion
        protected bool SetProperty<T>(ref T backingStore, T value,
            [CallerMemberName]string propertyName = "",
            Action onChanged = null)
        {
            if (EqualityComparer<T>.Default.Equals(backingStore, value))
                return false;

            backingStore = value;
            onChanged?.Invoke();
            OnPropertyChanged(propertyName);
            return true;
        }
    }
}

在代码中,您没有更改属性
Lamp1
。您正在更改lamp类
Name
中的属性。如果在lamp类中使用
Name
字段实现
INotifyPropertyChanged
,它将更新。对于当前代码,如果您将
Lamp1
更改为具有不同名称的
Lamp
的新实例,则它将记录更改,因为您正在更改
Lamp1
字段

public class Lamp : NotifyChange {  //NotifyChange is the INotifyPropertyChanged implementation in a base class

    private _Name;
    public Name{
        get{ return _Name; }
        set{ 
            if( _Name != value ) {
                _Name = value;
                OnPropertyChanged( nameof( Name ) );
            }
        }
    }
}

属性更改需要在更改发生的位置执行,否则它将不知道其已更改。希望这能解释为什么您没有在视图中显示更新。

除了Jorge Guerrero的答案之外,您可以尝试在XAML中的
Lamp1
绑定中添加以下内容,
UpdateSourceTrigger=PropertyChanged
我的ViewModelBase比这简单,但它实现了INotifyPropertyChanged,正如我所说,如果我将新实例设置为Lamp1,则视图将更新。所以我想我说对了?在您的版本中,我看到了与旧值的比较,但我没有类似的内容,而且,如果不创建新实例,该值不会更新。谢谢!这意味着通过绑定绑定到PropertyChangedEventHandler的方法在何时更新视图上实现了一些限制?它不是每次调用时都强制更新吗?这里有人知道为什么吗?@elg不,它总是实现更新它只是取决于你在哪里实现
propertychangedventhandler
,就像我在回答中说的那样。如果您正在更改名称,他们将在那里实现它,或者如果您正在创建lamp的新实例,请在那里实现它。
public Lamp Lamp1
        {
            get { return _lamp1; }
            set { SetProperty(ref _lamp1, value; }
        }
public class Lamp : NotifyChange {  //NotifyChange is the INotifyPropertyChanged implementation in a base class

    private _Name;
    public Name{
        get{ return _Name; }
        set{ 
            if( _Name != value ) {
                _Name = value;
                OnPropertyChanged( nameof( Name ) );
            }
        }
    }
}