将TreeView绑定到HierarchicalDataTemplate和DataTemplate,其中DataType是一个接口

时间:2013-08-06 15:45:33

标签: c# wpf interface treeview hierarchicaldatatemplate

我有一个复杂的问题,我一直努力工作一周,现在正在努力工作。我正在使用WPF .NET 4.5,MVVM模式和Prism。我想显示绑定到ObservableCollection<IScript> LoadedScripts

的TreeView
namespace Library.Data.Scripting    
{
    public interface IScript : INotifyPropertyChanged
    {
        ...

        IScriptDescription ScriptDescription { get; }

        ...
    }


    public interface IScriptDescription : INotifyPropertyChanged
    {
        ...

        string Name { get; }
        IEnumerable<ISectionDescription> Sections { get; }
        ScriptStatus Status { get; }

        ...
    }

    public interface ISectionDescription : INotifyPropertyChanged
    {
        ...

        string Name { get; }
        ScriptStatus Status { get; }

        ...
    }
}

我希望TreeView显示脚本列表和每个脚本,以便为脚本的部分创建子代。对于每个可见的节点,我想显示名称和状态。也就是说,IScript中的每个LoadedScripts都会显示ScriptDescription.NameScriptDescription.Status的文本框。对于每个子ISectionDescription,包含ISectionDescription.NameISectionDescription.Status

的文本框

这一切都相当简单,除了我绑定到Interfaces的事实。我发现我应该能够使用DataTemplateSelector来克服这个问题,但是我的树视图没有在我的模板中正确显示文本。相反,我在object.ToString()IScript获得ObservableCollection<IScript> LoadedScripts没有孩子的Output。我也没有在DataTemplate窗口中收到任何错误或警告。

我觉得我非常接近,但我无法正确显示我的数据。我已经确认我确实收到了我的数据,如果我为TreeView.ItemTemplate添加基本IScript,我就可以显示顶级namespace Library.App.GUI { public class ScriptDataTemplateSelector : DataTemplateSelector { public override DataTemplate SelectTemplate(object item, DependencyObject container) { FrameworkElement element = container as FrameworkElement; if (element != null && item != null && item is IScript) { return element.FindResource("ScriptTemplate") as HierarchicalDataTemplate; } else if (element != null && item != null && item is ISectionDescription) { return element.FindResource("SectionTemplate") as DataTemplate; } return null; } } } 节点。我不确定我做错了什么,非常感谢任何输入!

这是我的DataTemplateSelector:

namespace Library.App.GUI
{
    public class TestStatusViewModel
    {
        private IScriptManager ScriptManager;

        public ObservableCollection<IScript> LoadedScripts
        {
            get 
            { 
                return ScriptManager.LoadedScripts; 
            }
        }

        public TestStatusViewModel()
        {
            //Locate the ScriptManager in the MEF container using Microsoft.Practices.ServiceLocation.ServiceLocator
            ScriptManager = ServiceLocator.Current.GetInstance<IScriptManager>();
        }
    }
}

ViewModel:

<UserControl x:Class="Library.App.GUI.TestStatusView"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
            xmlns:local="clr-namespace:Library.App.GUI"
            xmlns:script="clr-namespace:Library.Data.Scripting;assembly=MTFCommon"
            xmlns:prism="clr-namespace:Microsoft.Practices.Prism;assembly=Microsoft.Practices.Prism"
            xmlns:sys="clr-namespace:System;assembly=mscorlib"
            mc:Ignorable="d" 
            d:DesignHeight="600" d:DesignWidth="200">


    <UserControl.Resources>
        <local:ScriptDataTemplateSelector x:Key="ScriptTemplateSelector"/>

        <HierarchicalDataTemplate  x:Key="ScriptTemplate" ItemsSource="{Binding ScriptDescription.Sections}">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition />
                </Grid.ColumnDefinitions>

                <TextBlock Grid.Column="0" TextAlignment="Left" Text="{Binding ScriptDescription.Name}" />
                <TextBlock Grid.Column="1" TextAlignment="Right" FontWeight="Bold" HorizontalAlignment="Stretch" Text="{Binding ScriptDescription.Status}" />
            </Grid>
        </HierarchicalDataTemplate>

        <DataTemplate x:Key="SectionTemplate">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition />
                </Grid.ColumnDefinitions>

                <TextBlock Grid.Column="0" TextAlignment="Left" Text="{Binding Name}" />
                <TextBlock Grid.Column="1" TextAlignment="Right" FontWeight="Bold" HorizontalAlignment="Stretch" Text="{Binding Status}" />
            </Grid>
        </DataTemplate>
    </UserControl.Resources>

    <ItemsControl HorizontalAlignment="Stretch">
            <TreeView Name="treeView" ItemTemplateSelector="{StaticResource ScriptTemplateSelector}" ItemsSource="{Binding LoadedScripts}" />
    </ItemsControl>

</UserControl>

这是我的XAML:

{{1}}

P.S。:Library.Data命名空间中的所有内容我无法亲自编辑,因为它是一个外部库。如果必须发生,我可以提出改变请求,但不愿意。

P.P.S。:这是我的第一个问题,如果我遗漏了任何重要信息,请告诉我。谢谢!

1 个答案:

答案 0 :(得分:2)

如果DataTemplateSelector无效,您可能需要查看element.FindResource是否返回任何内容。如果它返回null(或者您的as返回null),则ToString将用于显示树中的项目。