Иерархические шаблоны нескольких типов объектов в Silverlight - PullRequest
2 голосов
/ 22 марта 2010

Возможно ли и если да, каков наилучший способ реализовать следующую иерархическую структуру в элементе управления TreeView (4) silverlight? (где Item и Group являются классами, которые могут существовать в дереве).


Group
|
|-Item
|
|-Group
| |
| |-Item
| |
| |-Item
|
|-Item

Структура, конечно, может быть произвольно более сложной, чем эта, если это необходимо.

HierarchicalDataTemplates, кажется, способ приблизиться к этому, но у меня определенно возникают проблемы с пониманием того, как я могу применить шаблон для правильной интерпретации различных классов.

Аналогичный вопрос был задан для WPF, для ответа на который использовалось свойство TargetType в HierarchicalDataTemplate, но я не уверен, доступно ли это свойство в версии Silverlight, так как у меня нет доступа к нему в мое окружение.

Ответы [ 2 ]

2 голосов
/ 22 марта 2010

Для Silverlight вам может понадобиться создать конвертер, чтобы помочь сделать это. Например, «селектор шаблона данных целевого типа» или аналогичный.

Несмотря на то, что вы могли бы стать более продвинутыми, вот пример из среды модульного тестирования Silverlight, которая позволяет предоставлять экземпляры шаблонов данных для жестко закодированных типов. Обобщенная версия, вероятно, может быть сделана примерно за 20 минут.

Чтобы использовать это, вы должны предоставить экземпляры шаблонов данных - хотя в вашем случае вам, вероятно, потребуется сделать их иерархическими.

<local:DataTemplateSelector 
    x:Key="DetailsViewDataTemplate"
    DefaultDataTemplate="{StaticResource DefaultDataTemplate}"
    TestMethodTemplate="{StaticResource TestMethodDataTemplate}"
    TestClassTemplate="{StaticResource TestClassDataTemplate}"/>

А вот и реализация:

/// <summary>
/// A specialized data template selector.
/// </summary>
public sealed class DataTemplateSelector : IValueConverter
{
    /// <summary>
    /// Gets or sets the default data template.
    /// </summary>
    public DataTemplate DefaultDataTemplate { get; set; }

    /// <summary>
    /// Gets or sets the test method template.
    /// </summary>
    public DataTemplate TestMethodTemplate { get; set; }

    /// <summary>
    /// Gets or sets the test class template.
    /// </summary>
    public DataTemplate TestClassTemplate { get; set; }

    /// <summary>
    /// Initializes a new instance of the DataTemplateSelector type.
    /// </summary>
    public DataTemplateSelector()
    {
    }

    /// <summary>
    /// Convert a value to a data template.
    /// </summary>
    /// <param name="value">The value.</param>
    /// <param name="targetType">The target parameter.</param>
    /// <param name="parameter">ConverterParameter value.</param>
    /// <param name="culture">The culture parameter.</param>
    /// <returns>Returns the object.</returns>
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value != null)
        {
            Type type = value.GetType();

            if (typeof(TestMethodData).TypeHandle == type.TypeHandle)
            {
                return TestMethodTemplate;
            }
            else if (typeof(TestClassData).TypeHandle == type.TypeHandle)
            {
                return TestClassTemplate;
            }
        }

        return DefaultDataTemplate;
    }

    /// <summary>
    /// No 2-way databinding support.
    /// </summary>
    /// <param name="value">The value.</param>
    /// <param name="targetType">The target parameter.</param>
    /// <param name="parameter">ConverterParameter value.</param>
    /// <param name="culture">The culture parameter.</param>
    /// <returns>Returns the object.</returns>
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return null;
    }
}
1 голос
/ 11 ноября 2013

Моя реализация

<UserControl.Resources>

    <DataTemplate x:Key="DefaultDataTemplate">
        <TextBlock Text="Default"/>
    </DataTemplate>

    <DataTemplate x:Key="ConditionDataTemplate">
        <Grid>
            <TextBlock Text="{Binding ConditionType}" Margin="5" Width="100"/>
        </Grid>
    </DataTemplate>

    <DataTemplate x:Key="ButtonDataTemplate">
        <Grid>
            <Button Content="{Binding Name}"/>
        </Grid>
    </DataTemplate>

    <DataTemplate x:Key="FieldDataTemplate">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <ComboBox Grid.Column="0" ItemsSource="{Binding Fields}" SelectedItem="{Binding Name,Mode=TwoWay}" Margin="5,0,5,0"/>
            <ComboBox Grid.Column="1" ItemsSource="{Binding ConditionTypes}" SelectedItem="{Binding ConditionType,Mode=TwoWay}" Margin="5,0,5,0"/>
            <TextBox Grid.Column="2" Text="{Binding Value, Mode=TwoWay}" Margin="5" Width="100"/>
        </Grid>
    </DataTemplate>

    <local:DataTemplateSelector 
            x:Key="DetailsViewDataTemplate"
            DefaultDataTemplate="{StaticResource DefaultDataTemplate}"
            ConditionDataTemplate="{StaticResource ConditionDataTemplate}"
            FieldDataTemplate="{StaticResource FieldDataTemplate}"
            ButtonDataTemplate="{StaticResource ButtonDataTemplate}"/>
</UserControl.Resources>
<Grid>
    <sdk:TreeView ItemsSource="{Binding Tree}">
        <sdk:TreeView.ItemTemplate>
            <sdk:HierarchicalDataTemplate ItemsSource="{Binding ChildNodes}">
                    <ContentControl ContentTemplate="{Binding Converter={StaticResource DetailsViewDataTemplate}}" Content="{Binding}"/>
            </sdk:HierarchicalDataTemplate>
        </sdk:TreeView.ItemTemplate>
    </sdk:TreeView>
</Grid>

MainClass

    public class MainPageModel : BaseModel
{
    private ObservableCollection<object> _Tree;
    public ObservableCollection<object> Tree
    {
        get
        {
            return _Tree;
        }
        set
        {
            _Tree = value;
            Notify("Tree");
        }
    }

    public MainPageModel()
    {
        Tree = new ObservableCollection<object>();
        Tree.Add(new Condition()
        {
            ConditionType = "OR",
                ChildNodes = new ObservableCollection<object>()
                {
                    new Field()
                        {
                            Name = "Поле 2", 
                            ConditionType = "=",
                            Value = "3"
                    },
                    new Field()
                        {
                            Name = "Поле 3",
                            ConditionType = ">",
                            Value = "3"
                    },
                    new Field()
                        {
                            Name = "Поле 4",
                            ConditionType = "<",
                            Value = "3"
                    },
                    new Condition() 
                    { 
                        ConditionType = "AND" ,
                    ChildNodes = new ObservableCollection<object>()
                    {
                        new Field()
                            {
                                Name = "Поле 2",
                                ConditionType = "=", 
                                Value = "3"
                            },
                        new Field()
                            {
                                Name = "Поле 3",
                                ConditionType = ">",
                                Value = "3"

                        },
                        new Field()
                            {
                                Name = "Поле 4",
                                ConditionType = "<",
                                Value = "3"
                        },
                        new Button()
                        {
                                Name = "Добавить"
                        }
                    }
                }
            }
            });
        Notify("Tree");
    }
}

public static class PickList
{
    public static ObservableCollection<string> Fields
    {
        get
        {
            return new ObservableCollection<string>() { "Поле 1", "Поле 2", "Поле 3", "Поле 4" };
        }
    }

    public static ObservableCollection<string> ConditionType
    {
        get
        {
            return new ObservableCollection<string>() { ">", "<", "=" };
        }
    }
}

public class Condition : BaseModel
{
    private ObservableCollection<object> _ChildNodes;
    public ObservableCollection<object> ChildNodes
    {
        get { return _ChildNodes; }
        set { _ChildNodes = value; Notify("ChildNodes"); }
    }

    public string ConditionType { get; set; }
}

public class Field : BaseModel
{
    public ObservableCollection<string> Fields
    {
        get
        {
            return PickList.Fields;
        }
    }
    public ObservableCollection<string> ConditionTypes
    {
        get
        {
            return PickList.ConditionType;
        }
    }

    public string Name { get; set; }
    public string ConditionType { get; set; }
    public string Value { get; set; }
}

public class Button : BaseModel
{
    public string Name { get; set; }
}

Преобразователь

    public sealed class DataTemplateSelector : IValueConverter
{

    public DataTemplate ConditionDataTemplate { get; set; }

    public DataTemplate FieldDataTemplate { get; set; }

    public DataTemplate ButtonDataTemplate { get; set; }

    public DataTemplate DefaultDataTemplate { get; set; }

    public DataTemplateSelector()
    {
    }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value != null)
        {
            Type type = value.GetType();


            if (typeof(Condition).TypeHandle == type.TypeHandle)
            {
                return ConditionDataTemplate;
            }
            else if (typeof(Field).TypeHandle == type.TypeHandle)
            {
                return FieldDataTemplate;
            }
            else if (typeof(Button).TypeHandle == type.TypeHandle)
            {
                return ButtonDataTemplate;
            }
        }

        return DefaultDataTemplate;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return null;
    }
}

Я планирую добавить типы отображения поля DateTime, Bool, ...

...