【发布时间】:2012-09-21 15:47:43
【问题描述】:
编辑
有时工作的解决方案完全让我摆脱了最初的疑惑,为什么它首先会起作用。毕竟,这些项目不是可视树的一部分。最后,这是完全有道理的:
- 该集合中的按钮不在可视树中,因此元素绑定不起作用。
- 应用模板会将它们放入可视化树并绑定,如果此时应用,则开始工作。
- 这证实了可疑的竞争条件。
我的一位同事进行了一些扩展调试,也显示了该问题 - 在绑定成功的情况下,首先调用 OnApplyBinding。所以在不调整逻辑树的情况下使用集合是有缺陷的。
感谢您回到正轨的回复!
原帖
我有一个公开 ObservableCollection 的视图控件,我的视图可以包含任意元素,例如纽扣。注意按钮上的 ElementName 绑定:
<local:ViperView>
<local:ViperView.MenuItems>
<Button Content="{Binding ElementName=btn, Path=Content}" />
</local:ViperView.MenuItems>
<Grid>
<Button x:Name="btn" Content="HELLO WORLD" />
</Grid>
</local:ViperView>
控件的 ControlTemplate 只是使用 ItemsControl 呈现内容:
<ControlTemplate ...
...
<ItemsControl
x:Name="PART_NavigationMenuItemsHost"
ItemsSource="{Binding MenuItems, RelativeSource={RelativeSource TemplatedParent}}" />
</ControlTemplate>
上面的视图分配给我的主视图模型的 ActiveView 属性。主窗口只是通过数据绑定显示视图。
现在的问题:如果视图在创建后没有立即分配给视图模型,则该视图内的 ElementName 绑定无法可靠地工作。
ElementName 绑定的工作方式如下:
MainViewModel.ActiveView = new ViperView();
ElementName 绑定有时使用正常优先级:
var view = new ViperView();
Dispatcher.BeginInvoke(() => MainViewModel.ActiveView view);
如果视图模型属性设置为低优先级,ElementName 绑定总是失败:
var view = new ViperView();
Dispatcher.BeginInvoke(DispatcherPriority.Render, () => MainViewModel.ActiveView = view);
如果属性是从工作线程设置的,ElementName 绑定有时 有效(绑定引擎编组回 UI 线程):
var view = new ViperView();
Task.Factory.StartNew(() => MainViewModel.ActiveView = view);
ElementName 绑定总是失败如果工作线程有延迟:
var view = new ViperView();
var view = new ViperView();
Task.Factory.StartNew(() =>
{
Thread.Sleep(100);
MainViewModel.ActiveView = view;
});
我对此没有答案。这似乎与时间有关。例如,如果我在上面的任务示例中添加一个简短的 Thread.Sleep,这 总是 会导致绑定中断,而没有睡眠,它只是有时会中断。
这对我来说是一个很好的展示 - 任何指针都值得赞赏......
感谢您的建议 菲利普
【问题讨论】:
标签: wpf data-binding itemscontrol dispatcher