带有MasterDetails和ToggleButton的TreeView [英] TreeView with MasterDetails and ToggleButton

查看:81
本文介绍了带有MasterDetails和ToggleButton的TreeView的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在所选项目上创建一个具有MasterDetails的TreeView.

I want to create a TreeView with MasterDetails on selected Item.

问题是,即使父项已展开,子项也不会显示在我的SelectedItem中.不知何故,HierarchicalDataTemplate似乎迷路了.

The problem is, that no children are displayed in my SelectedItem, even when the parent is expanded. Somehow the HierarchicalDataTemplate seems to get lost.

也许我只是错误地使用了<TreeView.ItemTemplate>中的HierarchicalDataTemplate. 我应该从ItemsPanelTemplate还是类似的东西开始?目前没有任何线索.

Maybe I am just wrong with the HierarchicalDataTemplate in the <TreeView.ItemTemplate>. Should I start with ItemsPanelTemplate or something similar? Have no clue at the moment.

这是我的XAML:

<Window x:Class="TreeViewMasterDetails.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:TreeViewMasterDetails" 
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.Resources>
            <SolidColorBrush x:Key="GlyphBrush" Color="#444" />
            <BooleanToVisibilityConverter x:Key="booltoVisibilityConverter" />

            <PathGeometry x:Key="TreeArrow">
                <PathGeometry.Figures>
                    <PathFigureCollection>
                        <PathFigure IsFilled="True"
                            StartPoint="0 0"
                            IsClosed="True">
                            <PathFigure.Segments>
                                <PathSegmentCollection>
                                    <LineSegment Point="0 6"/>
                                    <LineSegment Point="6 0"/>
                                </PathSegmentCollection>
                            </PathFigure.Segments>
                        </PathFigure>
                    </PathFigureCollection>
                </PathGeometry.Figures>
            </PathGeometry>

            <Style x:Key="ExpandCollapseToggleStyle"
           TargetType="{x:Type ToggleButton}">
                <Setter Property="Focusable"
                Value="False"/>
                <Setter Property="Width"
                Value="16"/>
                <Setter Property="Height"
                Value="16"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type ToggleButton}">
                            <Border Width="16"
                            Height="16"
                            Background="Transparent"
                            Padding="5,5,5,5">
                                <Path x:Name="ExpandPath"
                              Fill="Transparent"
                              Stroke="#FF989898"
                              Data="{StaticResource TreeArrow}">
                                    <Path.RenderTransform>
                                        <RotateTransform Angle="135"
                                                 CenterX="3"
                                                 CenterY="3"/>
                                    </Path.RenderTransform>
                                </Path>
                            </Border>
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsMouseOver"
                                 Value="True">
                                    <Setter TargetName="ExpandPath"
                                    Property="Stroke"
                                    Value="#FF1BBBFA"/>
                                    <Setter TargetName="ExpandPath"
                                    Property="Fill"
                                    Value="Transparent"/>
                                </Trigger>

                                <Trigger Property="IsChecked"
                                 Value="True">
                                    <Setter TargetName="ExpandPath"
                                    Property="RenderTransform">
                                        <Setter.Value>
                                            <RotateTransform Angle="180"
                                                     CenterX="3"
                                                     CenterY="3"/>
                                        </Setter.Value>
                                    </Setter>
                                    <Setter TargetName="ExpandPath"
                                    Property="Fill"
                                    Value="#FF595959"/>
                                    <Setter TargetName="ExpandPath"
                                    Property="Stroke"
                                    Value="#FF262626"/>
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>

            <ControlTemplate TargetType="{x:Type TreeViewItem}" x:Key="selectedItemTemplate">
                <Grid Height="Auto" Background="SkyBlue">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"></RowDefinition>
                        <RowDefinition Height="Auto"></RowDefinition>
                        <RowDefinition Height="Auto"></RowDefinition>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="20"></ColumnDefinition>
                        <ColumnDefinition Width="Auto"></ColumnDefinition>
                    </Grid.ColumnDefinitions>
                    <ToggleButton x:Name="Expander"
                                      Style="{StaticResource ExpandCollapseToggleStyle}"
                                      IsChecked="{Binding Path=IsExpanded,RelativeSource={RelativeSource TemplatedParent}}"
                                      ClickMode="Press"
                                      Visibility="{Binding Path=HasItems,RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource booltoVisibilityConverter}}"/>

                    <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Id}"></TextBlock>
                    <TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Name}"></TextBlock>
                    <TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding Description}"></TextBlock>
                </Grid>
            </ControlTemplate>
        </Grid.Resources>

        <TreeView Height="Auto" 
                  HorizontalAlignment="Stretch" 
                  Margin="10" 
                  VerticalAlignment="Stretch" 
                  Width="Auto"
                  ItemsSource="{Binding Items}">
            <TreeView.ItemContainerStyle>
                <Style TargetType="TreeViewItem">
                    <Style.Triggers>
                        <Trigger Property="IsSelected" Value="True">
                            <Setter Property="Template" Value="{StaticResource selectedItemTemplate}"/>
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </TreeView.ItemContainerStyle>
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate DataType="x:Type local:NodeViewModel" ItemsSource="{Binding Children}">
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="20*" />
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="100*" />
                            <ColumnDefinition Width="100*" />
                            <ColumnDefinition Width="100*" />
                        </Grid.ColumnDefinitions>

                        <TextBlock Grid.Column="0" Text="{Binding Id}"></TextBlock>
                        <TextBlock Grid.Column="1" Text="----"></TextBlock>
                        <TextBlock Grid.Column="2" Text="{Binding Name}"></TextBlock>
                    </Grid>

                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>
    </Grid>
</Window>

请原谅XAML的massiv块,但是现在我不知道在哪里 原因在于.

Please excuse the massiv block of XAML, but right now I do not know where the cause lies.

还有我的ViewModel:

And my ViewModel:

public class NodeViewModel : ViewModelBase
{
    public string Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public bool IsExpanded { get; set; }
    public bool HasChildren  // perhaps this can be replaced by HasItems in TemplatedParent?
    {
        get
        {
            if (Children != null)
            {
                Children.Any();
            }

            return false;
        }
    }

    public ObservableCollection<NodeViewModel> Children { get; set; }
}

如何使用HierarchicalDataTemplate显示子级?为什么会迷路?

How can I display the children with my HierarchicalDataTemplate? Why it gets lost?

更新 在我的TreeViewItem样式中添加了一个setter,以便在选择时将IsExpanded设置为true, 并且ToggleButton似乎显示了此权限.

Update Have added a setter in my TreeViewItem Style to set IsExpanded to true on selection, and the ToggleButton seems to display this right.

有没有好的教程或可以找到如何处理分层数据模板的任何东西?

Is there any good tutorial or anything where I can find out how to deal with the hierarchical data template?

任何关于我如何进行的想法都会受到赞赏!

Any idea on how I can go on will be highly appreciated!

推荐答案

您尝试使用切换按钮模拟树视图项.我敢肯定会有一种方法,但这很复杂.如果您可以将扩展器按钮放在模板之外,请尝试以下解决方案.现在,更改Treeview项的视觉样式已内置在HierarchicalDataTemplate中.

You tried to emulate the treeview item with a toggle button. I'm sure there would be a way to do that, but it's complex. If you can live with the expander button being outside your template, try the following solution. Changing the visual style of the treeview item is now built into the HierarchicalDataTemplate.

您正在将TreeView绑定到尚未公开的ViewModel的属性Items,而HierarchicalDataTemplate使用了属性Children,我必须更改它,因为我还使用NodeViewModel作为根" ViewModel.

You are binding the TreeView to the property Items of a ViewModel you have not disclosed, while the HierarchicalDataTemplate uses the property Children, I had to change that because I use the NodeViewModel also as the 'root' ViewModel.

我认为使用DataTemplateSelector可以实现相同的目的.

I think the same could be achieved with a DataTemplateSelector.

Xaml:

<UserControl.DataContext>
    <local:NodeViewModel  />
</UserControl.DataContext>
<Grid>
    <Grid.Resources>
        <DataTemplate x:Key="notSelectedItemTemplate" DataType="{x:Type local:NodeViewModel}" >
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="20*" />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="100*" />
                    <ColumnDefinition Width="100*" />
                    <ColumnDefinition Width="100*" />
                </Grid.ColumnDefinitions>

                <TextBlock Grid.Column="0" Text="{Binding Id}"></TextBlock>
                <TextBlock Grid.Column="1" Text="----"></TextBlock>
                <TextBlock Grid.Column="2" Text="{Binding Name}"></TextBlock>
            </Grid>
        </DataTemplate>

        <DataTemplate x:Key="selectedItemTemplate" DataType="{x:Type local:NodeViewModel}">
            <Grid Height="Auto" Background="SkyBlue" TextElement.Foreground="Black">
                <Grid.RowDefinitions>
                    <!--<RowDefinition Height="Auto"></RowDefinition>-->
                    <RowDefinition Height="Auto"></RowDefinition>
                    <RowDefinition Height="Auto"></RowDefinition>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="20"></ColumnDefinition>
                    <ColumnDefinition Width="Auto"></ColumnDefinition>
                </Grid.ColumnDefinitions>

                <!--<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Id}"></TextBlock>-->
                <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Name}"></TextBlock>
                <TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Description}"></TextBlock>
            </Grid>
        </DataTemplate>
    </Grid.Resources>

    <TreeView Height="Auto" HorizontalAlignment="Stretch" Margin="10" VerticalAlignment="Stretch" Width="Auto" ItemsSource="{Binding Children}">
        <TreeView.Resources>
            <!-- remove normal selected item background -->
            <SolidColorBrush Color="Transparent" x:Key="{x:Static SystemColors.HighlightBrushKey}"/>
        </TreeView.Resources>
        <TreeView.ItemContainerStyle>
            <Style TargetType="{x:Type TreeViewItem}">
                <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
            </Style>
        </TreeView.ItemContainerStyle>
        <TreeView.ItemTemplate>
            <HierarchicalDataTemplate DataType="{x:Type local:NodeViewModel}" ItemsSource="{Binding Children}">
                <ContentPresenter x:Name="item" ContentTemplate="{StaticResource notSelectedItemTemplate}" />
                <HierarchicalDataTemplate.Triggers>
                    <DataTrigger Binding="{Binding IsSelected}" Value="True">
                        <Setter TargetName="item" Property="ContentTemplate" Value="{StaticResource selectedItemTemplate}" />
                    </DataTrigger>
                </HierarchicalDataTemplate.Triggers>
            </HierarchicalDataTemplate>
        </TreeView.ItemTemplate>
    </TreeView>
</Grid>

NodeViewModel(添加了IsSelected属性):

NodeViewModel (added IsSelected property):

public class NodeViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    private ObservableCollection<NodeViewModel> _children;
    public ObservableCollection<NodeViewModel> Children { get { return _children; } set { _children = value; OnPropertyChanged("Children"); } }


    private string _id;
    public string Id { get { return _id; } set { _id = value; OnPropertyChanged("ID"); } }
    private string _name;
    public string Name { get { return _name; } set { _name = value; OnPropertyChanged("ID"); } }
    private string _description;
    public string Description { get { return _description; } set { _description = value; OnPropertyChanged("Description"); } }
    private bool _isExpanded;
    public bool IsExpanded { get { return _isExpanded; } set { _isExpanded = value; OnPropertyChanged("IsExpanded"); } }
    private bool _isSelected;
    public bool IsSelected { get { return _isSelected; } set { _isSelected = value; OnPropertyChanged("IsSelected"); } }
    public bool HasChildren  // perhaps this can be replaced by HasItems in TemplatedParent?
    {
        get
        {
            if (Children != null)
            {
                Children.Any();
            }

            return false;
        }
    }

    private static bool _setData = true; // hack for example data

    public NodeViewModel()
    {
        if (_setData)
        {
            _setData = false;
            SetExampleData();
        }
    }

    public void SetExampleData()
    {
        Children = new ObservableCollection<NodeViewModel>()
        {
            new NodeViewModel() { Name = "1", Description = "One"    },
            new NodeViewModel() { Name = "2", Description = "Two"    },
            new NodeViewModel() { Name = "3", Description = "Three"  },
            new NodeViewModel() { Name = "4", Description = "Four"   },
            new NodeViewModel() { Name = "5", Description = "Five"   },
            new NodeViewModel() { Name = "6", Description = "Six"    },
            new NodeViewModel() { Name = "7", Description = "Seven"  },
            new NodeViewModel() { Name = "8", Description = "Eight"  }
        };

        Children[0].Children = new ObservableCollection<NodeViewModel>() 
        {  
            new NodeViewModel() { Name = "1.1", Description="One.One" },
            new NodeViewModel() { Name = "1.2", Description="One.Two" },
            new NodeViewModel() { Name = "1.3", Description="One.Three" }
        };

        Children[0].Children[0].Children = new ObservableCollection<NodeViewModel>() 
        {  
            new NodeViewModel() { Name = "1.1.1", Description="One.One.One" },
            new NodeViewModel() { Name = "1.1.2", Description="One.One.Two" },
        };

        Children[1].Children = new ObservableCollection<NodeViewModel>() 
        {  
            new NodeViewModel() { Name = "2.1", Description="Two.One" },
            new NodeViewModel() { Name = "2.2", Description="Two.Two" },
        };
    }
}

这篇关于带有MasterDetails和ToggleButton的TreeView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆