【问题标题】:INotifyPropertyChange doesn't fire [closed]INotifyPropertyChanged 不会触发 [关闭]
【发布时间】:2018-01-15 13:06:43
【问题描述】:

编辑:请参阅类结构。 INotifyPropertyChanged 在 ComMethodA 情况下工作正常并按预期触发事件。为什么它在 ComMethodB 的情况下不起作用?

编辑 2: 请参考视图模型代码。

在我的应用程序中,我有几个视图和视图模型。 所有的 ViewModel 都继承自 ViewModelBase,它创建了我的模型的单例对象,我们将其称为 MainModel,结构如下:

public class MainModel : INotifyPropertyChanged
{
   public string Name {get; set; }
   public List<ISystem> SystemsList{get;set;}   
   public IComMethod ComMethodA {get;set;}   // TEST 1
   public MainModel()
   {
       ComMethodA = new ClassC();
      // let's assume that the other props are initialized
   }
}

public class System: ISystem, INotifyPropertyChanged 
{
   public IComMethod ComMethodB {get;set;}   // TEST 2
   public System()
   {
      ComMethodB = new classC(); // classC implements INotifyPropertyChanged, IComMethod
   }
}

public class ClassC() : IComMethod, INotifyPropertyChanged 
{
    public bool isOpen {get;set;}
    public ClassC()
    {
        // ctor..
    }
}

ViewModelA:

    ctor() 
    {
        MainModel.SystemsList[0].ComMethodB.PropertyChanged += ComMethodB_PropertyChanged;
        MainModel.ComMethodA.PropertyChanged += ComMethodA_PropertyChanged;     
    }
    private void ComMethodB_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
          MessageBox.Show("TextB");
    }
    private void ComMethodA_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
      MessageBox.Show("TextA");
    }

视图模型 B:

MainModel.ComMethodA.isOpen = true; // FIRES event in ViewModelA
MainModel.SystemsList[0].ComMethodB.isOpen = true; // DOESN'T fires event in ViewModelA

在 ViewModelA 中,我正在为 TEST 1 和 TEST 2 属性实现属性更改事件。 在 ViewModelB 中,我正在更改“isOpen”属性。

问题是该事件仅在“ComMethodA”场景中触发,但我希望它在“ComMethodB”场景中触发。

谢谢

【问题讨论】:

  • 你必须提出这个事件。在提供的代码中没有任何地方表明正在引发事件。建议您创建一个具有通用功能的基础视图模型并从中派生其他类
  • @gr1d3r INotifyPropertyChanged 只是一个接口。它没有实际功能
  • 正如FCin所说,实现INotifyPropertyChanged只是意味着你的类必须有具有适当参数和返回类型的方法,你仍然必须实现它们并调用它们。
  • 没有看到实现,我们很难/不可能帮助您找出问题所在。另外,你怎么知道事件没有被触发?
  • 事件在哪里引发?仅更改 isOpen 不会自动引发 PropertyChanged 事件。如果您的 ViewModelBase 实现确实解决了这个问题,它是如何做到的?

标签: c# wpf mvvm


【解决方案1】:

我怀疑问题出在您未发布的代码中。如果我不得不猜测,我会说它与 ViewModelBase 类中的 MainModel 单例有关 - 也许 ViewModelA/B 正在获取 MainModel 的不同实例?

我填写了您问题代码中的空白,它似乎对我有用。 注意:由于命名空间冲突,我将类 System 重命名为 Systems。

using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;

namespace WpfApp9
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            // Setup the ViewModels
            var vmA = new ViewModelA();
            var vmB = new ViewModelB();

            // Test ViewModelB
            vmB.DoIt();
        }
    }

    public class MainModel : INotifyPropertyChanged
    {
        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        protected bool SetProperty<T>(ref T field, T value, [CallerMemberName]string name = null)
        {
            if (Equals(field, value))
            {
                return false;
            }
            field = value;
            this.OnPropertyChanged(name);
            return true;
        }
        protected void OnPropertyChanged([CallerMemberName]string name = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }
        #endregion

        #region Property List<ISystem> SystemsList
        private List<ISystem> _SystemsList;
        public List<ISystem> SystemsList { get { return _SystemsList; } set { SetProperty(ref _SystemsList, value); } }
        #endregion

        #region Property IComMethod ComMethodA
        private IComMethod _ComMethodA;
        public IComMethod ComMethodA { get { return _ComMethodA; } set { SetProperty(ref _ComMethodA, value); } }
        #endregion

        public MainModel()
        {
            SystemsList = new List<ISystem>() { new Systems() };
            ComMethodA = new ClassC();
        }
    }

    public interface ISystem
    {
        IComMethod ComMethodB { get; set; }
    }
    public interface IComMethod : INotifyPropertyChanged
    {
        bool isOpen { get; set; }
    }

    public class Systems : ISystem, INotifyPropertyChanged
    {
        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        protected bool SetProperty<T>(ref T field, T value, [CallerMemberName]string name = null)
        {
            if (Equals(field, value))
            {
                return false;
            }
            field = value;
            this.OnPropertyChanged(name);
            return true;
        }
        protected void OnPropertyChanged([CallerMemberName]string name = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }
        #endregion

        #region Property IComMethod ComMethodB
        private IComMethod _ComMethodB;
        public IComMethod ComMethodB { get { return _ComMethodB; } set { SetProperty(ref _ComMethodB, value); } }
        #endregion

        public Systems()
        {
            ComMethodB = new ClassC();
        }
    }

    public class ClassC : IComMethod, INotifyPropertyChanged
    {
        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        protected bool SetProperty<T>(ref T field, T value, [CallerMemberName]string name = null)
        {
            if (Equals(field, value))
            {
                return false;
            }
            field = value;
            this.OnPropertyChanged(name);
            return true;
        }
        protected void OnPropertyChanged([CallerMemberName]string name = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }
        #endregion

        #region Property bool isOpen
        private bool _isOpen;
        public bool isOpen { get { return _isOpen; } set { SetProperty(ref _isOpen, value); } }
        #endregion
    }

    public class ViewModelBase : INotifyPropertyChanged
    {
        public static MainModel MainModel { get; } = new MainModel();

        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        protected bool SetProperty<T>(ref T field, T value, [CallerMemberName]string name = null)
        {
            if (Equals(field, value))
            {
                return false;
            }
            field = value;
            this.OnPropertyChanged(name);
            return true;
        }
        protected void OnPropertyChanged([CallerMemberName]string name = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }
        #endregion
    }

    public class ViewModelA : ViewModelBase
    {
        public ViewModelA()
        {
            MainModel.SystemsList[0].ComMethodB.PropertyChanged += ComMethodB_PropertyChanged;
            MainModel.ComMethodA.PropertyChanged += ComMethodA_PropertyChanged;
        }

        private void ComMethodB_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            MessageBox.Show("TextB");
        }

        private void ComMethodA_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            MessageBox.Show("TextA");
        }
    }

    public class ViewModelB : ViewModelBase
    {
        public ViewModelB()
        {
        }

        public void DoIt()
        {
            MainModel.ComMethodA.isOpen = true; // this fired off the "TextA" messagebox
            MainModel.SystemsList[0].ComMethodB.isOpen = true; // this fired off the "TextB" messagebox
        }
    }
}

【讨论】:

  • 谢谢,现在可以使用了。接口对象初始化的一个副本造成了这个问题。
  • 太好了,很高兴我能提供帮助。太糟糕了,其他所有人都被未显示(但已实现)的 INPC 界面所抛弃。
猜你喜欢
  • 2015-09-24
  • 2021-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-01
  • 2018-09-11
  • 2013-06-18
相关资源
最近更新 更多