【发布时间】:2015-09-15 07:36:06
【问题描述】:
我已经为此工作了数周...我正在创建一个在主窗口中使用 Avalon Dock 2.0 的 WPF 应用程序。我正在尝试以 MVVM 方式使用对接管理器,因此我将DockingManager.DocumentsSource 绑定到我的MainViewModel 中的ObservableCollection<object> 属性。我还创建了一个自定义DataTemplateSelector 并将其绑定到DockingManager.LayoutItemTemplateSelector。我遇到的问题:
- 我将
ViewModel添加到文档源。 - 我的自定义
DataTemplateSelector.SelectTemplate()被调用。 -
SelectTemplate()中的 item 参数是System.Windows.Controls.ContentPresenter,而不是我添加的ViewModel对象。 - 即使我返回正确的
DataTemplate,它最终也会绑定到ContentPresenter,而不是ContentPresenter中包含的ViewModel。
我设法在一个简单的 WPF 项目中复制了这个问题,这里是相关代码:
主窗口:
<!-- MainWindow markup DataContext is bound to
I omitted the usual xmlns declarations -->
<Window
xmlns:xcad="http://schemas.xceed.com/wpf/xaml/avalondock"
xmlns:local="clr-namespace:AvalonTest"
Title="MainWindow">
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<Grid>
<xcad:DockingManager DocumentsSource="{Binding Docs}">
<xcad:DockingManager.LayoutItemTemplateSelector>
<local:TestTemplateSelector>
<local:TestTemplateSelector.TheTemplate>
<DataTemplate>
<local:TestView/>
</DataTemplate>
</local:TestTemplateSelector.TheTemplate>
</local:TestTemplateSelector>
</xcad:DockingManager.LayoutItemTemplateSelector>
<xcad:LayoutRoot>
<xcad:LayoutPanel Orientation="Vertical">
<xcad:LayoutAnchorablePane/>
<xcad:LayoutDocumentPane/>
</xcad:LayoutPanel>
</xcad:LayoutRoot>
</xcad:DockingManager>
</Grid>
</Window>
主视图模型:
class MainViewModel
{
//Bound to DockingManager.DocumentsSource
public ObservableCollection<object> Docs { get; private set; }
public MainViewModel()
{
Docs = new ObservableCollection<object>();
Docs.Add(new TestViewModel());
}
}
数据模板选择器:
class TestTemplateSelector : DataTemplateSelector
{
public TestTemplateSelector() {}
public DataTemplate TheTemplate { get; set; }
//When this method is called, item is always a ContentPresenter
//ContentPresenter.Content will contain the ViewModel I add
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
//Just return the only template no matter what
return TheTemplate;
}
}
测试视图:
<!-- TestTemplateSelector will always return this TestView -->
<UserControl x:Class="AvalonTest.TestView"
xmlns:local="clr-namespace:AvalonTest">
<Grid>
<StackPanel Orientation="Vertical">
<TextBox Text="{Binding TestText}"/>
<Button Content="A Button"/>
</StackPanel>
</Grid>
</UserControl>
TestViewModel:
//TestView.DataContext should be set to this, but instead
//it gets set to a containing ContentPresenter
class TestViewModel : ObservableObject
{
private string testText = "TESTTESTTEST";
public string TestText
{
get { return testText; }
set
{
testText = value;
RaisePropertyChanged("TestText");
}
}
}
结果:
TestView 未正确绑定到TestViewModel,因此“TESTTESTTEST”不会出现在TextBox 中。我检查了Avalon Dock's sample MVVM project,他们的DataTemplateSelector 总是得到ViewModel 而不是ContentPresenter。我做错了什么?
【问题讨论】:
-
顺便说一句,有人可以看看我的问题中突出显示的语法吗? c# 代码似乎没有正确突出显示。
-
刚刚用c#扩展你的标签,现在代码高亮工作了。
-
我怀疑
LayoutItemTemplateSelector是按照 ContentTemplate 的完成方式建模的,如果我没记错的话,它有一些 slightly different behavior... 即它使用.Content来表示.DataContext,.Content是一个包装你的 ViewModel 的 ContentPresenter -
如果你使用
<local:TestView DataContext="{TemplateBinding Content}" />之类的东西会起作用吗? -
@Rachel,只是为了确保我尝试使用 xaml 手动绑定 DataContext 并且它有效。当然,在这种情况下,如果我可以选择手动绑定 DataContext,我们就不需要 TemplateSelector :P
标签: c# .net wpf mvvm avalondock