【问题标题】:Hierarchical templating multiple object types in silverlight在 silverlight 中分层模板化多种对象类型
【发布时间】:2010-03-22 15:37:25
【问题描述】:

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


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

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

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

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

【问题讨论】:

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


    【解决方案1】:

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

    【讨论】:

    • 感谢您的回复,很抱歉我花了这么长时间才跟进此事。我确实尝试实施您的解决方案,但没有成功。我无法弄清楚在模板数据绑定中使用转换器的语法。我想像 ItemsTemplate="{Binding Converter={StaticResource ConverterInstance}}" 这样的东西,但我无法让它工作。然而,我确实觉得你的方法是个好方法。我创建了一个 TreeNode 类,其中包含一个子集合和对我的数据对象的引用。缺点是我无法根据类型设置树中每个条目的样式。
    【解决方案2】:

    我的实现

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

    【讨论】:

      猜你喜欢
      • 2017-09-20
      • 2019-08-20
      • 2013-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多