在silverlight中分层模板化多个对象类型

时间:2010-03-22 15:37:26

标签: silverlight treeview silverlight-4.0 silverlight-toolkit hierarchicaldatatemplate

是否可能,如果是这样,在silverlight(4)TreeView控件中实现以下层次结构的最佳方法是什么? (其中Item和Group是树中可以存在的类)。


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

如果需要,结构当然可以比这更复杂。

HierarchicalDataTemplates似乎是解决这个问题的方法,但我特别难以理解如何应用模板来正确解释不同的类。

类似的问题被要求WPF,其答案是在HierarchicalDataTemplate上使用了TargetType属性,但我不确定该属性是否在silverlight版本中可用,因为我似乎无法访问它我的环境。

2 个答案:

答案 0 :(得分:2)

对于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 :(得分:1)

我的实施

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

我打算添加Field显示类型DateTime,Bool,...