WPF - ObservableCollection 绑定失败 - .NET 4.0
快速摘要
- 在我的应用程序 GUI 中的网格中没有显示项目
- 启动时,网格中会列出正确的列(拾取的集合类型)
- CollectionChanged 事件在网格绑定到的 ObservableCollection 上触发
- 输出窗口中没有绑定错误(绑定成功,但未注册委托)
MyView.xaml
.
.
.
<UserControl.Resources>
<xcdg:DataGridCollectionViewSource
x:Key="items"
Source="{Binding Path=Items}"
AutoFilterMode="And" >
</xcdg:DataGridCollectionViewSource>
</UserControl.Resources>
<xcdg:DataGridControl
Name="dataGrid"
ReadOnly="True"
ItemsSource="{Binding Source={StaticResource items}}"
.
.
.
MyView.xaml.cs 构造函数
public MyView()
{
if (!DesignerProperties.GetIsInDesignMode(this))
DataContext = new MyViewModel().Tree;
initializeComponent();
}
MyViewModel.cs 关键部分
public MyTree Tree { get; set; }
public MyViewModel()
{
Tree = new MyTree();
}
MyTree.cs关键部分
public ObservableCollection<Item> Items{ get; private set; }
public MyTree()
{
Items= new ObservableCollection<Item>();
Items.CollectionChanged += delegate { Console.WriteLine("Trigger"); };
}
每次添加和删除时都会打印触发器,但 UI 仍然认为集合是空的并且不知道更新。如果没有我的额外委托 Items.CollectionChanged
是 null
(即解析的 Xaml 不会导致侦听器添加到集合中)
- 我在尝试时做错了什么 绑定我的
DataGridCollectionViewSource
到 可观察集合?
我很高兴提供更多细节,并尝试从我的用例中抽象出问题的核心内容。集合的嵌套可能看起来很荒谬,但它基本上是树中节点的集合,以便更快地访问。
提前致谢!
编辑
通过将 PresentationTraceSources.TraceLevel=High
添加到我的 Xaml,我得到了一些更详细的输出。
ItemsSource="{Binding Source={StaticResource orders}, PresentationTraceSources.TraceLevel=High}"
在这里,我认为问题在于默认更新触发器解析为PropertyChanged
,而我希望默认值是CollectionChanged
。但我仍然不知道该怎么办。
BindingExpression (hash=43320496): Default mode resolved to OneWay
BindingExpression (hash=43320496): Default update trigger resolved to PropertyChanged
BindingExpression (hash=43320496): Attach to Xceed.Wpf.DataGrid.DataGridControl.ItemsSource (hash=9150720)
BindingExpression (hash=43320496): Resolving source
BindingExpression (hash=43320496): Found data context element: <null> (OK)
BindingExpression (hash=43320496): Use View from DataGridCollectionViewSource (hash=9026257)
BindingExpression (hash=43320496): Activate with root item <null>
BindingExpression (hash=43320496): Replace item at level 0 with <null>, using accessor {DependencyProperty.UnsetValue}
BindingExpression (hash=43320496): GetValue at level 0 from <null> using <null>: <null>
BindingExpression (hash=43320496): TransferValue - got raw value <null>
BindingExpression (hash=43320496): TransferValue - using final value <null>
BindingExpression (hash=43320496): Got PropertyChanged event from DataGridCollectionViewSource (hash=9026257) for View
BindingExpression (hash=43320496): Deactivate
BindingExpression (hash=43320496): Replace item at level 0 with {NullDataItem}
BindingExpression (hash=43320496): Use View from DataGridCollectionViewSource (hash=9026257)
BindingExpression (hash=43320496): Activate with root item DataGridCollectionView (hash=54545236 Count=0)
BindingExpression (hash=43320496): Replace item at level 0 with DataGridCollectionView (hash=54545236 Count=0), using accessor {DependencyProperty.UnsetValue}
BindingExpression (hash=43320496): GetValue at level 0 from DataGridCollectionView (hash=54545236 Count=0) using <null>: DataGridCollectionView (hash=54545236 Count=0)
BindingExpression (hash=43320496): TransferValue - got raw value DataGridCollectionView (hash=54545236 Count=0)
BindingExpression (hash=43320496): TransferValue - using final value DataGridCollectionView (hash=54545236 Count=0)
Quick summary
- No items show up in my Grid in the GUI of my Application
- Correct columns are listed in grid when it fires up (Picked up collection type)
- CollectionChanged event fires on the ObservableCollection the grid is bound to
- No binding error in the output window (Binds successfully but doesn't register delegate)
MyView.xaml
.
.
.
<UserControl.Resources>
<xcdg:DataGridCollectionViewSource
x:Key="items"
Source="{Binding Path=Items}"
AutoFilterMode="And" >
</xcdg:DataGridCollectionViewSource>
</UserControl.Resources>
<xcdg:DataGridControl
Name="dataGrid"
ReadOnly="True"
ItemsSource="{Binding Source={StaticResource items}}"
.
.
.
MyView.xaml.cs Constructor
public MyView()
{
if (!DesignerProperties.GetIsInDesignMode(this))
DataContext = new MyViewModel().Tree;
initializeComponent();
}
MyViewModel.cs key parts
public MyTree Tree { get; set; }
public MyViewModel()
{
Tree = new MyTree();
}
MyTree.cs key parts
public ObservableCollection<Item> Items{ get; private set; }
public MyTree()
{
Items= new ObservableCollection<Item>();
Items.CollectionChanged += delegate { Console.WriteLine("Trigger"); };
}
Trigger gets printed on every addition and deletion but the UI still thinks the collection is empty and isn't aware of the updates. Without my extra delegate Items.CollectionChanged
is null
(ie the parsed Xaml doesn't cause a listener to be added to the collection)
- What am I doing wrong in trying to
bind myDataGridCollectionViewSource
to an
ObservableCollection?
Happy to give more detail, I've tried to abstract away from my use case to the bare bones of the issue. The nesting of the collection may seem ridiculous but it's basically a collection of the nodes in the tree for faster access.
Thanks in advance!
EDIT
By adding PresentationTraceSources.TraceLevel=High
to my Xaml I got some more detailed output.
ItemsSource="{Binding Source={StaticResource orders}, PresentationTraceSources.TraceLevel=High}"
Here I think the problem is that Default update trigger resolved to PropertyChanged
where I would expect the default to be CollectionChanged
. I'm still not sure what to do about this though.
BindingExpression (hash=43320496): Default mode resolved to OneWay
BindingExpression (hash=43320496): Default update trigger resolved to PropertyChanged
BindingExpression (hash=43320496): Attach to Xceed.Wpf.DataGrid.DataGridControl.ItemsSource (hash=9150720)
BindingExpression (hash=43320496): Resolving source
BindingExpression (hash=43320496): Found data context element: <null> (OK)
BindingExpression (hash=43320496): Use View from DataGridCollectionViewSource (hash=9026257)
BindingExpression (hash=43320496): Activate with root item <null>
BindingExpression (hash=43320496): Replace item at level 0 with <null>, using accessor {DependencyProperty.UnsetValue}
BindingExpression (hash=43320496): GetValue at level 0 from <null> using <null>: <null>
BindingExpression (hash=43320496): TransferValue - got raw value <null>
BindingExpression (hash=43320496): TransferValue - using final value <null>
BindingExpression (hash=43320496): Got PropertyChanged event from DataGridCollectionViewSource (hash=9026257) for View
BindingExpression (hash=43320496): Deactivate
BindingExpression (hash=43320496): Replace item at level 0 with {NullDataItem}
BindingExpression (hash=43320496): Use View from DataGridCollectionViewSource (hash=9026257)
BindingExpression (hash=43320496): Activate with root item DataGridCollectionView (hash=54545236 Count=0)
BindingExpression (hash=43320496): Replace item at level 0 with DataGridCollectionView (hash=54545236 Count=0), using accessor {DependencyProperty.UnsetValue}
BindingExpression (hash=43320496): GetValue at level 0 from DataGridCollectionView (hash=54545236 Count=0) using <null>: DataGridCollectionView (hash=54545236 Count=0)
BindingExpression (hash=43320496): TransferValue - got raw value DataGridCollectionView (hash=54545236 Count=0)
BindingExpression (hash=43320496): TransferValue - using final value DataGridCollectionView (hash=54545236 Count=0)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
如果您直接绑定到项目而不是使用静态源,它会起作用吗?
我对静态项目源没有太多经验,但静态这个词让我认为它是一次性绑定
Does it work if you bind directly to your Items instead of using a Static source?
<xcdg:DataGridControl Name="dataGrid" ItemsSource="{Binding Path=Items}" />
I don't have much experience with static item sources, but the word static makes me think its a one-time binding
如果您尝试将 Grid 直接绑定到
Items
属性,而不是绑定到CollectionViewSource
会怎样?如果有效,则问题出在CollectionViewSource
到集合的绑定上,而不是 Grid 到CollectionViewSource
的绑定上。What if you try binding the Grid directly to the
Items
property, rather than to theCollectionViewSource
? If that works, then the problem is with the binding of theCollectionViewSource
to your collection, rather than the Grid's binding to theCollectionViewSource
.您必须设置
CollectionViewSource
的Source
属性:You have to set the
Source
property of theCollectionViewSource
:您可以尝试为 CollectionViewSource 指定一个名称,然后在加载数据后在后面的代码中调用 CollectionViewSource.View.Refresh() 方法。
很多时候,问题是即使您将视图设置为 ObservableCollection,CollectionViewSource 也不会自动更新。
网上有人发布了一个很好的 AutoRefreshingObservableCollection 类,我一直在使用它并且运行良好。
尝试一下,如果它能解决您的问题,请告诉我。我也有该 AutoRefreshingObservableCollection 的代码,如果您需要,请回复,我可以将其放在我的网站或其他地方。
Something you can try is give the CollectionViewSource a name and then in the code behind call the CollectionViewSource.View.Refresh() method on it after you have loaded it with data.
Many times the problem is that the CollectionViewSource doesn't automatically update even if you make the view an ObservableCollection.
Someone on the web posted a nice class for an AutoRefreshingObservableCollection which I've been using and works well.
Give this a try and let me know if it solves your issue. I have the code for that AutoRefreshingObservableCollection too if you need, reply and I can drop it on my website or something.