我已经在这几周了...我正在创建一个在主窗口中使用Avalon Dock 2.0的WPF应用程序。我试图以MVVM方式使用Docking Manager,因此DockingManager.DocumentsSource
绑定到ObservableCollection<object>
中的MainViewModel
属性。我还创建了一个自定义DataTemplateSelector
并将其绑定到DockingManager.LayoutItemTemplateSelector
。我遇到的问题是:
ViewModel
。DataTemplateSelector.SelectTemplate()
已被调用。SelectTemplate()
中的item参数是System.Windows.Controls.ContentPresenter
,而不是我添加的ViewModel
对象。DataTemplate
,它也会被绑定到ContentPresenter
,而不是ViewModel
中包含的ContentPresenter
。我设法在一个简单的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>
MainViewModel:
class MainViewModel
{
//Bound to DockingManager.DocumentsSource
public ObservableCollection<object> Docs { get; private set; }
public MainViewModel()
{
Docs = new ObservableCollection<object>();
Docs.Add(new TestViewModel());
}
}
DataTemplateSelector:
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;
}
}
TestView:
<!-- 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
。我做错了什么?
答案 0 :(得分:5)
在TestTemplateSelector上更改SelectTemplate的定义,如下所示:
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
//check if the item is an instance of TestViewModel
if (item is TestViewModel)
return TheTemplate;
//delegate the call to base class
return base.SelectTemplate(item, container);
}
您应该始终检查传递的项是否是目标视图模型的实例,如果不是,则将调用委托给基类,以便WPF可以处理您不关心的对象。