2

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


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

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

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

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

4

2 回答 2

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;
    }
}
于 2010-03-22T19:21:41.410 回答
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>

主类

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

于 2013-11-11T17:16:04.097 回答