将DataGrid嵌入到WPF Treeview节点中

时间:2012-08-13 16:40:13

标签: wpf datagrid treeview datatemplate hierarchicaldatatemplate

我需要在 treeview 中显示层次结构。但是细节应该显示在数据网格

How I'd like it to be

我如何编写模板来实现这一目标?我现在误解模板中的smth。

    <TreeView ItemsSource="{Binding Path=Categories}">
        <TreeView.Resources>
            <HierarchicalDataTemplate DataType="{x:Type stackProjects:Category}" ItemsSource="{Binding Path=SubCategories}">
                <TextBlock Margin="3" Text="{Binding Path=CategoryName}"/>
            </HierarchicalDataTemplate>

            <HierarchicalDataTemplate DataType="{x:Type stackProjects:SubCategory}" ItemsSource="{Binding Path=Details}">
                <TextBlock Text="{Binding Path=SubCategoryName}"/>
            </HierarchicalDataTemplate>

            <DataTemplate DataType="{x:Type stackProjects:Detail}" >
                <StackPanel Orientation="Horizontal">
                    <TextBlock Margin="3" Text="{Binding Path=Name}"/>
                    <TextBlock Margin="3" Text=" - "/>
                    <TextBlock Margin="3" Text="{Binding Path=Info}"/>
                </StackPanel>
            </DataTemplate>
        </TreeView.Resources>
    </TreeView>

1 个答案:

答案 0 :(得分:8)

我找到了解决方法。我必须明白,Details应该作为一个集合呈现在一个具有IEnumerable属性的元素中。可能它不是最好的解决方案,但它确实有效。

我需要创建一个转换器来将我的集合包装成单个。

public class BoxingItemsConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var values = value as IEnumerable;
        var type = parameter as Type;

        if (values == null || type == null)
            return null;

        if (type.GetInterfaces().Any(x => x == typeof (IItemsWrapper)))
        {
            var instance = (IItemsWrapper) type.Assembly.CreateInstance(type.FullName);
            instance.Items = (IEnumerable) value;
            //returned value should be IEnumerable with one element. 
            //Otherwise we will not see children nodes
            return new List<IItemsWrapper> {instance};
        }
        return null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

包装器的示例:

internal interface IItemsWrapper
{
    IEnumerable Items { get; set; }
}

public class ItemsWrapper : IItemsWrapper
{
    public IEnumerable Items { get; set; }
}

public class DetailItemsWrapper : ItemsWrapper{}

public class InvoiceItemsWrapper:ItemsWrapper{}

和xaml。它不需要很多改变。您只需要使用Boxing转换器并将Type设置为在converter参数中返回。

<TreeView ItemsSource="{Binding Path=Categories}">
    <TreeView.Resources>
        <HierarchicalDataTemplate DataType="{x:Type wpfProj:Category}" ItemsSource="{Binding Path=SubCategories}">
            <TextBlock Margin="4" Text="{Binding Path=CategoryName}"/>
        </HierarchicalDataTemplate>

        <HierarchicalDataTemplate DataType="{x:Type wpfProj:SubCategory}" 
                                  ItemsSource="{Binding Path=Details, Converter={StaticResource boxingItems}, ConverterParameter={x:Type wpfProj:DetailItemsWrapper}}" >
            <StackPanel>
                <TextBlock Margin="4" Text="{Binding Path=SubCategoryName}"/>
            </StackPanel>
        </HierarchicalDataTemplate>

        <DataTemplate DataType="{x:Type wpfProj:DetailItemsWrapper}" >
            <DataGrid ItemsSource="{Binding Path=Items}"/>  
        </DataTemplate>
    </TreeView.Resources>
</TreeView>

我已将sample上传到dropbox。 这是它的样子:

DataGrid for TreeView nodes