【问题标题】:TreeView with MasterDetails and ToggleButton带有 MasterDetails 和 ToggleButton 的 TreeView
【发布时间】:2013-03-16 09:50:18
【问题描述】:

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

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

也许我对 <TreeView.ItemTemplate> 中的 HierarchicalDataTemplate 有误。 我应该从 ItemsPanelTemplate 还是类似的东西开始?暂时不知道。

这是我的 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 的大规模块,但现在我不知道在哪里 原因在于。

还有我的 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 显示子项?为什么会丢失?

更新 在我的 TreeViewItem 样式中添加了一个设置器,以便在选择时将 IsExpanded 设置为 true, 并且 ToggleButton 似乎显示正确。

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

任何关于我如何继续的想法都将受到高度赞赏!

【问题讨论】:

    标签: c# wpf xaml treeview hierarchicaldatatemplate


    【解决方案1】:

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

    您将 TreeView 绑定到您尚未披露的 ViewModel 的属性 Items,而 HierarchicalDataTemplate 使用属性 Children,我不得不更改它,因为我也使用 NodeViewModel 作为“根”ViewModel。

    我认为同样可以使用 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 属性):

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

    【讨论】:

    • 你是对的,我有另一个包含节点的 ViewModel 并没有发布那个,但是将 nodeviewmodel 作为 root 是可以的。非常感谢你。唯一不起作用的是扩展选定的节点。如何做到这一点?
    • 由于您的评论,我理解了您的问题。我已经编辑了答案来解决它。
    • 太棒了!效果很好!非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-26
    • 2017-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-23
    相关资源
    最近更新 更多