ObservableCollection 未更新 C# WPF 中的多重绑定
我有一个 TreeView,它从数据绑定 ObservableCollections 创建其所有项目。我有一个 GameNode 对象的层次结构,每个对象都有两个 ObservableCollections。一个集合具有 EntityAttrib 对象,另一个集合具有 GameNode 对象。您可以说 GameNode 对象代表文件夹,EntityAttrib 代表文件。为了在同一个 TreeView 中显示 attrib 和 GameNode,我使用了多重绑定。 这一切在启动时工作正常,但是当我在层次结构中的某个位置添加新的 GameNode 时,TreeView 不会更新。我在转换器方法中设置了一个断点,但在添加新的 GameNode 时不会调用它。看来 ObservableCollection 没有通知 MultiBinding 的更改。如果我注释掉 MultiBinding 并仅绑定 GameNode 集合,它会按预期工作。
XAML:
<HierarchicalDataTemplate DataType="{x:Type local:GameNode}">
<HierarchicalDataTemplate.ItemsSource>
<MultiBinding Converter="{StaticResource combineConverter}">
<Binding Path="Attributes" />
<Binding Path="ChildNodes" />
</MultiBinding>
</HierarchicalDataTemplate.ItemsSource>
<TextBlock Text="{Binding Path=Name}" ContextMenu="{StaticResource EntityCtxMenu}"/>
</HierarchicalDataTemplate>
C#:
public class GameNode
{
string mName;
public string Name { get { return mName; } set { mName = value; } }
GameNodeList mChildNodes = new GameNodeList();
public GameNodeList ChildNodes { get { return mChildNodes; } set { mChildNodes = value; } }
ObservableCollection<EntityAttrib> mAttributes = new ObservableCollection<EntityAttrib>();
public ObservableCollection<EntityAttrib> Attributes { get { return mAttributes; } set { mAttributes = value; } }
}
GameNodeList 是 ObservableCollection 的子类
I have a TreeView that creates all its items from databound ObservableCollections. I have a hierarchy of GameNode objects, each object has two ObservableCollections. One collections has EntityAttrib objects and the other have GameNode objects. You could say that the GameNode object represents folders and EntityAttrib represents files. To display both attrib and GameNodes in the same TreeView I use Multibinding.
This all works fine in startup, but when I add a new GameNode somewhere in the hierarchy the TreeView is not updated. I set a breakpoint in my converter method but it's not called when adding a new GameNode. It seems that the ObservableCollection is not notifying the MultiBinding of the change. If I comment out the MultiBinding and only bind the GameNode collection it works as expected.
XAML:
<HierarchicalDataTemplate DataType="{x:Type local:GameNode}">
<HierarchicalDataTemplate.ItemsSource>
<MultiBinding Converter="{StaticResource combineConverter}">
<Binding Path="Attributes" />
<Binding Path="ChildNodes" />
</MultiBinding>
</HierarchicalDataTemplate.ItemsSource>
<TextBlock Text="{Binding Path=Name}" ContextMenu="{StaticResource EntityCtxMenu}"/>
</HierarchicalDataTemplate>
C#:
public class GameNode
{
string mName;
public string Name { get { return mName; } set { mName = value; } }
GameNodeList mChildNodes = new GameNodeList();
public GameNodeList ChildNodes { get { return mChildNodes; } set { mChildNodes = value; } }
ObservableCollection<EntityAttrib> mAttributes = new ObservableCollection<EntityAttrib>();
public ObservableCollection<EntityAttrib> Attributes { get { return mAttributes; } set { mAttributes = value; } }
}
GameNodeList is a subclassed ObservableCollection
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
最好的方法(仅当您的 EntityAttrib 和 GameNode 是从同一基类继承的两个不同的类时)实际上是定义两个数据模板,如下所示。
这样更好,因为以后更容易记住。考虑文件系统对象,FileInfo 和 DirectoryInfo 类实际上都是从共享公共属性的 FileSystemInfo 类派生的。
您应该有一个基类“BaseGameNode”,其中包含一些内容,“GameNode”和“GameEntityAttribNode”均派生自“BaseGameNode”。它们应该只有一个 Children 属性,该属性是 BaseGameNode 类型的可观察集合,但其项目实例应该根据需要而不同。
您可以定义多个模板,只要它们有区别,系统会自动为节点的子节点选择类型。
您绑定的值不会刷新,因为它们不是依赖属性,也不会通知更改。由于多重绑定根本不会检测集合更改事件,除非集合的引用/实例发生更改。当您更改集合中的项目时,属性/属性的实际实例保持不变。
当您绑定 ItemsSource = collection 时, ItemsSource 将侦听 CollectionChange 事件并相应地更新项目。
The best way to do (only if your EntityAttrib and GameNode are two different classes inherited from same base class) would be actually defining two data templates as below.
This is better because its easier to recollect later on. Consider file system objects, both FileInfo and DirectoryInfo classes are actually derived from FileSystemInfo class which shares common property.
You should have a baseclass, "BaseGameNode" , have something in it, "GameNode" and "GameEntityAttribNode" both derived from "BaseGameNode". And they should have only one Children property that is observable collection of type BaseGameNode but its item instance should be different as needed.
You can define multiple templates provided they have something to distinguish, the type will be automatically chosen for the children of the node.
Value you have bound will not refresh because they are not dependency property neither they notify on change. Since multibinding will not detect collection change event at all unless the reference/instance of collection changes. When you change an item in collection your actual instance of attributes/properties remains same.
When you bind ItemsSource = collection, its the ItemsSource that will listen for CollectionChange event and update the items accordingly.