Wpf 与ObservableCollection绑定的列表框未随集合更新

Wpf 与ObservableCollection绑定的列表框未随集合更新,wpf,xaml,observablecollection,Wpf,Xaml,Observablecollection,我有下一个型号: public class MyModel { public ObservableCollection<MyObject> MyList {get; set;} } public class MyObject { MyObservableDictionary MyDictionary {get; set;} } public class MyObservableDictionary : ObservableCollection<EnymVal

我有下一个型号:

public class MyModel
{
    public ObservableCollection<MyObject> MyList {get; set;}
}

public class MyObject
{
   MyObservableDictionary MyDictionary {get; set;}
}

public class  MyObservableDictionary : ObservableCollection<EnymValue>
{
}

public class EnymValue : INotifyPropertyChanged
{
  private MyEnum key;
    private string value;

    public MyEnum Key
    {
        get
        {
            return this.key;
        }
        set
        {
            this.key = value;
            NotifyPropertyChanged("Key");
        }
    }
    public string Value
    {
        get
        {
            return this.value;
        }
        set
        {
            this.value = value;
            NotifyPropertyChanged("Value");
        }
    }

    public LanguageValue(MyEnum key, string value)
    {
        this.Key = key;
        this.Value = value;
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public void NotifyPropertyChanged([System.Runtime.CompilerServices.CallerMemberName]string propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

public enum MyEnum
{
}
公共类MyModel
{
公共ObservableCollection MyList{get;set;}
}
公共类MyObject
{
MyObservableDictionary MyDictionary{get;set;}
}
公共类MyObservableDictionary:ObservableCollection
{
}
公共类EnymValue:INotifyPropertyChanged
{
私钥;
私有字符串值;
公共髓鞘密钥
{
得到
{
返回此.key;
}
设置
{
this.key=值;
NotifyPropertyChanged(“密钥”);
}
}
公共字符串值
{
得到
{
返回此.value;
}
设置
{
这个值=值;
NotifyPropertyChanged(“价值”);
}
}
公共语言值(MyEnum键、字符串值)
{
这个。键=键;
这个。值=值;
}
公共事件属性更改事件处理程序属性更改;
public void NotifyPropertyChanged([System.Runtime.CompilerServices.CallerMemberName]字符串propertyName=”“)
{
if(PropertyChanged!=null)
{
PropertyChanged(这是新的PropertyChangedEventArgs(propertyName));
}
}
}
公共枚举髓鞘
{
}
在视图中,我有一个列表框:

<ListBox x:Name="MyList" SelectionMode="Single" ItemsSource="{Binding Path=MyList, Mode=OneWay}">
     <ListBox.ItemTemplate>
        <DataTemplate>
             <TextBlock Text="{Binding Path=MyDictionary, Mode=OneWay, Converter={StaticResource myEnumToTextConverter}}" />
         </DataTemplate>
      </ListBox.ItemTemplate>
</ListBox>

(myEnumToTextConverter converter只是从集合中选择第一个元素并返回它的值,或者在集合为null或空时返回某个指定的常量)

当任何
EnymValue
值发生更改时,我希望在视图中更新模型的列表框。 是否有可能以某种方式实现这一点?

当前,当
更改时,视图不会更新。
我试图从INotifyPropertyChanged继承
EnymValue
,但这没有帮助。属性更新时,在
EnymValue上看起来像
PropertyChanged==null
。NotifyPropertyChanged

ObservableCollection
能够在集合本身更改(元素被添加或删除)时通知UI有关更改的信息。但是,
ObservableCollection
不知道在您修改其中一个项目时发生的更改。要解决此问题,您可以订阅可观察集合的
CollectionChange
事件,并在添加新项目时,订阅新项目的PropertyChanged。当引发PropertyChanged事件时,您可以触发列表上的通知
OnPropertyChanged(()=>MyItems)在实现此解决方案时应小心,并记住取消订阅事件,以避免内存泄漏


您可以在中看到我的意思的示例。

ObservableCollection
能够在集合本身发生更改(元素被添加或删除)时通知UI更改。但是,
ObservableCollection
不知道在您修改其中一个项目时发生的更改。要解决此问题,您可以订阅可观察集合的
CollectionChange
事件,并在添加新项目时,订阅新项目的PropertyChanged。当引发PropertyChanged事件时,您可以触发列表上的通知
OnPropertyChanged(()=>MyItems)在实现此解决方案时应小心,并记住取消订阅事件,以避免内存泄漏


您可以在中看到我的意思的示例。

您的
MyDictionary
应该强制刷新。最简单的方法是重新分配其旧值,并在MyObject中实现INPC,如下所示:

public class MyObject: INotifyPropertyChanged
    {
        MyObservableDictionary _myDictionary;
        public MyObservableDictionary MyDictionary {
            get
            {
                return _myDictionary;
            }
            set
            {
                _myDictionary = value;
                OnPropertyChanged("MyDictionary");
            }
        }

        public MyObject()
        {
            MyDictionary = new MyObservableDictionary();
        }

        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string prop)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(prop));
        }
    }
更改值的示例代码:

private void Button_Click(object sender, RoutedEventArgs e)
{
    // vm is ViewModel instance, vm is DataContext set for Window

    var old = vm.MyList[0].MyDictionary;
    vm.MyList[0].MyDictionary[0].Value = "aaaa";
    vm.MyList[0].MyDictionary = old;
}

我对此进行了测试,它将更改后的值显示为“aaaa”。

您的
MyDictionary
应该强制刷新。最简单的方法是重新分配其旧值,并在MyObject中实现INPC,如下所示:

public class MyObject: INotifyPropertyChanged
    {
        MyObservableDictionary _myDictionary;
        public MyObservableDictionary MyDictionary {
            get
            {
                return _myDictionary;
            }
            set
            {
                _myDictionary = value;
                OnPropertyChanged("MyDictionary");
            }
        }

        public MyObject()
        {
            MyDictionary = new MyObservableDictionary();
        }

        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string prop)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(prop));
        }
    }
更改值的示例代码:

private void Button_Click(object sender, RoutedEventArgs e)
{
    // vm is ViewModel instance, vm is DataContext set for Window

    var old = vm.MyList[0].MyDictionary;
    vm.MyList[0].MyDictionary[0].Value = "aaaa";
    vm.MyList[0].MyDictionary = old;
}

我对此进行了测试,它将更改后的值显示为“aaaa”。

与您的操作方式不同。该
绑定
不会订阅
INotifyCollectionChanged
,因为您要将集合绑定到
字符串
属性。因此,当您更改集合时,没有人会听到它,绑定也不会更新目标。这不是您的操作方式。该
绑定
不会订阅
INotifyCollectionChanged
,因为您要将集合绑定到
字符串
属性。因此,当您更改集合时,没有人会听到它,绑定也不会更新目标。@EdPlunkett我刚刚测试了建议的解决方案,它按照我的预期工作。我的意思是OnPropertyChanged(“MyItems”)并不像您提到的那样被忽略。如果需要,我可以提供代码来证明它。你为什么认为应该忽略它?我很确定我试过了,但没有成功。我以前就错了。只是测试了一下,你是对的,它就像你说的那样工作。谢谢你提醒我注意这一点。@EdPlunkett我刚刚测试了提议的解决方案,它按照我的预期工作。我的意思是OnPropertyChanged(“MyItems”)并不像您提到的那样被忽略。如果需要,我可以提供代码来证明它。你为什么认为应该忽略它?我很确定我试过了,但没有成功。我以前就错了。只是测试了一下,你是对的,它就像你说的那样工作。谢谢你提醒我注意这件事。