سؤال

I've got a complex question I've been working on for a good week now trying to work correctly. I am using WPF .NET 4.5, the MVVM pattern, and Prism. I want to display a TreeView that binds to an ObservableCollection<IScript> LoadedScripts:

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

        ...
    }
}

I want the TreeView to display the list of scripts and each script to have children for the script's sections. For each node that is visible, I want to show the Name and Status. That is, for each IScript in LoadedScripts show a textbox of ScriptDescription.Name and ScriptDescription.Status. For each child ISectionDescription, a TextBox containing ISectionDescription.Name and ISectionDescription.Status.

This is all fairly straightforward, except for the fact that I'm binding to Interfaces. I found how I'm supposed to be able to overcome this, using a DataTemplateSelector, but my treeview isn't displaying the text correctly in my templates. Instead, I am getting the object.ToString() for the IScripts in my ObservableCollection<IScript> LoadedScripts with no children. I'm not getting any kind of errors or warnings in the Output window either.

I feel like I am really close but I can't get it to correctly display my data. I have verified I am indeed getting my data and if I put a basic DataTemplate for TreeView.ItemTemplate I am able to display the top-level IScript nodes. I'm not sure what I'm doing wrong, any input is much appreciated!

Here's my DataTemplateSelector:

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

    }
}

The ViewModel:

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

Here's my XAML:

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

P.S.: Everything in the Library.Data namespace I am not able to personally edit since it is an external library. I can put in a request to have it changed if that must happen, but prefer not.

P.P.S.: This is my first SO question, please let me know if I missed any important information. Thanks!

هل كانت مفيدة؟

المحلول

If your DataTemplateSelector not working, you might want to check to see if element.FindResource is returning anything. If it returns null (or your as returns null), then the ToString will be used to display the items in the tree.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top