C# ListBox ObservableCollection属性未更新

C# ListBox ObservableCollection属性未更新,c#,wpf,mvvm,listbox,observablecollection,C#,Wpf,Mvvm,Listbox,Observablecollection,在获取包含ObservableCollection的列表框时遇到一些问题,该列表框将在项目的属性发生更改时更新。项所在的对象类型正在使用INotifyPropertyChanged和PropertyChanged()。(对我来说)有趣的是列表框不能按我想要/需要的方式工作,但我可以用另一种方式让它工作。我的MVVM基于以下文章/代码: 我正试图模拟他的工作区,以包含BuildRepository中的服务器配置。但是,我不想让“AllServerConfigs”成为该工作区中的一个选项卡,而是希望

在获取包含ObservableCollection的列表框时遇到一些问题,该列表框将在项目的属性发生更改时更新。项所在的对象类型正在使用INotifyPropertyChanged和PropertyChanged()。(对我来说)有趣的是列表框不能按我想要/需要的方式工作,但我可以用另一种方式让它工作。我的MVVM基于以下文章/代码:

我正试图模拟他的工作区,以包含BuildRepository中的服务器配置。但是,我不想让“AllServerConfigs”成为该工作区中的一个选项卡,而是希望它成为左侧的一个列表框,用户可以在其中打开已关闭选项卡的配置。列表框正在更新以添加/删除,但属性没有更新(例如,如果保存新名称)

这是
主窗口.XAML
;datacontext设置为“RepositoryViewModel”

这里是
ServerConfigViewModel

    public class ServerConfigViewModel : WorkspaceViewModel, IDataErrorInfo
    {
        readonly ServerConfig _serverConfig;
        readonly BuildRepository _buildRepository;

        #region Server Config Fields
        public string Name
        {
            get
            {
                return _serverConfig.Name;
            }
            set
            {
                if (value == _serverConfig.Name)
                {
                    return;
                }

                _serverConfig.Name = value;
                base.OnPropertyChanged("Name");
            }
        }


        #region Presentation Properties
        public override string DisplayName
        {
            get
            {
                if (_serverConfig.Name == null)
                {
                    return "New Server";
                }
                return _serverConfig.Name;
            }
        }


        #region Constructors
        public ServerConfigViewModel(ServerConfig serverConfig, BuildRepository buildRepository)
        {
            if (serverConfig == null)
            {
                throw new ArgumentNullException("serverConfig");
            }

            if (buildRepository == null)
            {
                throw new ArgumentNullException("buildRepository");
            }

            _serverConfig = serverConfig;
            _buildRepository = buildRepository;
        }
        #endregion

        #region Public Methods
        public void Save()
        {
            if (!_serverConfig.IsValid)
            {
                throw new InvalidOperationException("Server Config is not valid, cannot be saved");
            }
            if (this.IsNewServerConfig)
            {
                _buildRepository.AddServerConfig(_serverConfig);
            }
            base.OnPropertyChanged("DisplayName");
        }
        #endregion
    }
    public class AllConfigsViewModel : WorkspaceViewModel
    {
        #region Properties
        readonly BuildRepository _buildRepository;

        #endregion

        #region Constructor
        public AllConfigsViewModel(BuildRepository buildRepository)
        {
            base.DisplayName = "All Configs";
            _buildRepository = buildRepository;
            _buildRepository.ServerConfigAdded += this.OnServerConfigAddedToRepository;
            this.CreateAllServerConfigs();
        }

        void CreateAllServerConfigs()
        {
            List<ServerConfigViewModel> all =
                (from config in _buildRepository.GetServerConfigs()
                 select new ServerConfigViewModel(config, _buildRepository)).ToList();

            foreach (ServerConfigViewModel scvm in all)
                scvm.PropertyChanged += this.OnServerConfigViewModelPropertyChanged;

            this.AllServerConfigs = new ObservableCollection<ServerConfigViewModel>(all);
            this.AllServerConfigs.CollectionChanged += this.OnCollectionChanged;

        }


        #endregion

        #region Public Interface
        public ObservableCollection<ServerConfigViewModel> AllServerConfigs
        {
            get;
            private set;
        }
        #endregion

        #region Event Handling
        void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.NewItems != null && e.NewItems.Count != 0)
                foreach (ServerConfigViewModel configVm in e.NewItems)
                    configVm.PropertyChanged += this.OnServerConfigViewModelPropertyChanged;

            if (e.OldItems != null && e.OldItems.Count != 0)
                foreach (ServerConfigViewModel configVm in e.OldItems)
                    configVm.PropertyChanged -= this.OnServerConfigViewModelPropertyChanged;

        }
        void OnServerConfigViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            string DisplayName = "DisplayName";
            (sender as ServerConfigViewModel).VerifyPropertyName(DisplayName);
            if (e.PropertyName == DisplayName)
            {
                this.OnPropertyChanged("AllServerConfigs");
            }
        }

        void OnServerConfigAddedToRepository(object sender, ServerConfigAddedEventArgs e)
        {
            var viewModel = new ServerConfigViewModel(e.NewServerConfig, _buildRepository);
            this.AllServerConfigs.Add(viewModel);
            //this.OnPropertyChanged("AllServerConfigs");
        }
        #endregion
    }
这里是
AllConfigsViewModel

    public class ServerConfigViewModel : WorkspaceViewModel, IDataErrorInfo
    {
        readonly ServerConfig _serverConfig;
        readonly BuildRepository _buildRepository;

        #region Server Config Fields
        public string Name
        {
            get
            {
                return _serverConfig.Name;
            }
            set
            {
                if (value == _serverConfig.Name)
                {
                    return;
                }

                _serverConfig.Name = value;
                base.OnPropertyChanged("Name");
            }
        }


        #region Presentation Properties
        public override string DisplayName
        {
            get
            {
                if (_serverConfig.Name == null)
                {
                    return "New Server";
                }
                return _serverConfig.Name;
            }
        }


        #region Constructors
        public ServerConfigViewModel(ServerConfig serverConfig, BuildRepository buildRepository)
        {
            if (serverConfig == null)
            {
                throw new ArgumentNullException("serverConfig");
            }

            if (buildRepository == null)
            {
                throw new ArgumentNullException("buildRepository");
            }

            _serverConfig = serverConfig;
            _buildRepository = buildRepository;
        }
        #endregion

        #region Public Methods
        public void Save()
        {
            if (!_serverConfig.IsValid)
            {
                throw new InvalidOperationException("Server Config is not valid, cannot be saved");
            }
            if (this.IsNewServerConfig)
            {
                _buildRepository.AddServerConfig(_serverConfig);
            }
            base.OnPropertyChanged("DisplayName");
        }
        #endregion
    }
    public class AllConfigsViewModel : WorkspaceViewModel
    {
        #region Properties
        readonly BuildRepository _buildRepository;

        #endregion

        #region Constructor
        public AllConfigsViewModel(BuildRepository buildRepository)
        {
            base.DisplayName = "All Configs";
            _buildRepository = buildRepository;
            _buildRepository.ServerConfigAdded += this.OnServerConfigAddedToRepository;
            this.CreateAllServerConfigs();
        }

        void CreateAllServerConfigs()
        {
            List<ServerConfigViewModel> all =
                (from config in _buildRepository.GetServerConfigs()
                 select new ServerConfigViewModel(config, _buildRepository)).ToList();

            foreach (ServerConfigViewModel scvm in all)
                scvm.PropertyChanged += this.OnServerConfigViewModelPropertyChanged;

            this.AllServerConfigs = new ObservableCollection<ServerConfigViewModel>(all);
            this.AllServerConfigs.CollectionChanged += this.OnCollectionChanged;

        }


        #endregion

        #region Public Interface
        public ObservableCollection<ServerConfigViewModel> AllServerConfigs
        {
            get;
            private set;
        }
        #endregion

        #region Event Handling
        void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.NewItems != null && e.NewItems.Count != 0)
                foreach (ServerConfigViewModel configVm in e.NewItems)
                    configVm.PropertyChanged += this.OnServerConfigViewModelPropertyChanged;

            if (e.OldItems != null && e.OldItems.Count != 0)
                foreach (ServerConfigViewModel configVm in e.OldItems)
                    configVm.PropertyChanged -= this.OnServerConfigViewModelPropertyChanged;

        }
        void OnServerConfigViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            string DisplayName = "DisplayName";
            (sender as ServerConfigViewModel).VerifyPropertyName(DisplayName);
            if (e.PropertyName == DisplayName)
            {
                this.OnPropertyChanged("AllServerConfigs");
            }
        }

        void OnServerConfigAddedToRepository(object sender, ServerConfigAddedEventArgs e)
        {
            var viewModel = new ServerConfigViewModel(e.NewServerConfig, _buildRepository);
            this.AllServerConfigs.Add(viewModel);
            //this.OnPropertyChanged("AllServerConfigs");
        }
        #endregion
    }

由于ListBox的DisplayMemberPath绑定到DisplayName,请添加

base.OnPropertyChanged("DisplayName");
到ServerConfigViewModel中的Name属性的setter之后

base.OnPropertyChanged("Name");

这应该告诉它在绑定DisplayName的任何位置刷新视图。

我会说创建一个新项目,用更少的代码尝试它,如果有任何问题,返回StackOverflow并提出问题。很难查看您的代码并诊断问题。嗨,Dilshod,我已经更新了我的原始帖子,删除了所有与ObservableCollections和ListBox无关的代码。这是一个全新的项目,是尽我所能的小(以我在WPF的技能)。我只从我需要的MVVM示例中提取代码,并将其转换为我自己的对象类型。我只是不明白为什么在一个可观察集合中显示的项目不更新,而在另一个集合中显示的项目看起来完全相同。太棒了!你能发布MainWindow.xaml.csI的代码吗?我已经用
MainWindow.xaml.cs
更新了底部的帖子,它是一个空代码。我还发布了
App.cs
的代码。只是尝试了一下,没有改变。
base.OnPropertyChanged(“DisplayName”)
按钮也会调用
Save
按钮,这是我真正想要更新它的时候。
base.OnPropertyChanged("Name");