c# - Avalon Dock 2.0 LayoutItemTemplateSelector 给出了 ContentPresenter 而不是 ViewModel

标签 c# .net wpf mvvm avalondock

我已经在这几个星期了...我正在创建一个在主窗口中使用 Avalon Dock 2.0 的 WPF 应用程序。我正在尝试以 MVVM 方式使用对接管理器,所以我有 DockingManager.DocumentsSource绑定(bind)到 ObservableCollection<object>我的属性(property)MainViewModel .我还创建了一个自定义 DataTemplateSelector并将其绑定(bind)到 DockingManager.LayoutItemTemplateSelector .我遇到的问题:

  1. 我添加一个 ViewModel到文件来源。
  2. 我的习惯 DataTemplateSelector.SelectTemplate()被称为。
  3. SelectTemplate() 中的项目参数是 System.Windows.Controls.ContentPresenter而不是 ViewModel我添加的对象。
  4. 即使我返回正确的 DataTemplate , 它最终绑定(bind)到 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>

主视图模型:

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;
    }
}

测试 View :

<!-- 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>

测试 View 模型:

//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");
        }
    }
}

结果:

enter image description here

TestView未正确绑定(bind)到 TestViewModel因此“TESTTESTTEST”不会出现在 TextBox 中.我已经 checkout Avalon Dock's sample MVVM project和他们的 DataTemplateSelector总是得到 ViewModel而不是 ContentPresenter .我做错了什么?

最佳答案

如下更改 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);
    }

您应该始终检查传递的项目是否是目标 View 模型的实例,如果不是,则将调用委托(delegate)给基类,以便 WPF 可以处理您不关心的对象。

关于c# - Avalon Dock 2.0 LayoutItemTemplateSelector 给出了 ContentPresenter 而不是 ViewModel,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32580286/

相关文章:

c# - 如何从 MahApps.Metro 将带有操作的按钮添加到 ShowInputAsync

c# - 为什么通过 OleDb 在 Access 数据库中调用我的更新查询不起作用?

c# - 如何签署 ClickOnce 应用程序

c# - 分割并添加空间

wpf - 使用 Add_SelectedValueChanged() 从 ComboBox 分配值

.net - 使用 UI 自动化时避免切换焦点

c# - 使用 KeyVault secret 覆盖 Azure 应用服务和本地中的应用程序设置

c# - 从 C# 设置/运行 PostgreSQL

c# - WPF 线程错误(处理了无效操作异常)

.net - 您可以在线程池中排队的工作项数量是否有限制?