locked
How get/set TreeViewItem height? RRS feed

  • Question

  • I need TreeViewItem height for extend drag&drop.

    But TreeViewItem height is NaN. How to set it with xaml?

    <TreeView Name="treeView" Grid.Column="0" AllowDrop="True">
                        <TreeView.Resources>
                            <Style TargetType="{x:Type TreeViewItem}">
                                <Setter Property="Height" Value="30"/>
                                <EventSetter Event="TreeViewItem.DragOver" Handler="treeView_DragOver"/>
                                <EventSetter Event="TreeViewItem.Drop" Handler="treeView_Drop"/>
                                <EventSetter Event="TreeViewItem.MouseMove" Handler="treeView_MouseMove"/>
                                <Setter Property="HeaderTemplate">
                                    <Setter.Value>
                                        <DataTemplate>
                                            <StackPanel Orientation="Horizontal">
                                                <Image Name="img" Width="16" Height="16" Stretch="Fill" 
                                                       Source="{Binding RelativeSource=
                                                    {RelativeSource Mode=FindAncestor, 
                                                    AncestorType={x:Type TreeViewItem}},Path=Tag, Converter={StaticResource TagImageConwerter}}"/>
                                                <TextBlock Text="{Binding}" />
                                            </StackPanel>
                                        </DataTemplate>
                                    </Setter.Value>
                                </Setter>
                            </Style>
                        </TreeView.Resources>
                    </TreeView>

    Especially

    <Setter Property="Height" Value="30"/>
    not set item height to 30 but whole tree height to 30. How set item height to 16 or 18?

    Thursday, April 28, 2016 5:26 PM

Answers

  • A treeviewitem is a headereditemscontrol. The default stuff in a node is the header AND an itemscontrol for the children.

    You should use a datatemplate / hierarchicaldatatemplate rather that setting the headertemplate like that.

    For example:

            <TreeView Name="trvFamilies" ItemsSource="{Binding Families}" Grid.Row="1" Grid.ColumnSpan="2">
                <TreeView.Resources>
                    <HierarchicalDataTemplate DataType="{x:Type local:Family}" ItemsSource="{Binding Members}">
                        <StackPanel Orientation="Horizontal"
                                    Height="32"
                                    >
                            <Label VerticalAlignment="Center" FontFamily="WingDings" Content="1"/>
                            <TextBlock Text="{Binding Name}" />
                        </StackPanel>
                    </HierarchicalDataTemplate>
                    <DataTemplate DataType="{x:Type local:FamilyMember}">
                        <StackPanel Orientation="Horizontal"
                                    Height="32"
                                    x:Name="sp">
                            <TextBlock Tag="{Binding DataContext.Name, 
                                RelativeSource={RelativeSource AncestorType=TreeViewItem , AncestorLevel=2}
                                }" 
                                Text="{Binding Name}" >
                            </TextBlock>
                            <TextBlock Text=" (" Foreground="Green" />
                            <TextBlock Text="{Binding Age}" Foreground="Green" />
                            <TextBlock Text=" years)" Foreground="Green" />
                        </StackPanel>
                    </DataTemplate>
                </TreeView.Resources>
            </TreeView>
    Here, each item will be 32 height.


    Hope that helps.

    Technet articles: WPF: Layout Lab; All my Technet Articles

    • Proposed as answer by David Roller Thursday, April 28, 2016 6:43 PM
    • Marked as answer by Xavier Xie-MSFT Thursday, May 5, 2016 12:14 PM
    Thursday, April 28, 2016 5:54 PM
  • They're types.

        public class Family
        {
            public Family()
            {
                this.Members = new ObservableCollection<FamilyMember>();
            }
            public string Name { get; set; }
            public ObservableCollection<FamilyMember> Members { get; set; }
        }
    
        public class FamilyMember
        {
            public string Name { get; set; }
            public int Age { get; set; }
        }

    and local is the xmlns reference to the project.

    <Window x:Class="wpf_TreeView.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:wpf_TreeView"

    That's the same markup and code  I posted in your other thread.

    Using datatype= on a datatemplate tells wpf to template an object matching that type using the template provided.


    Hope that helps.

    Technet articles: WPF: Layout Lab; All my Technet Articles

    • Proposed as answer by DotNet Wang Thursday, May 5, 2016 7:16 AM
    • Marked as answer by Xavier Xie-MSFT Thursday, May 5, 2016 12:14 PM
    Thursday, April 28, 2016 7:17 PM
  • It depends what you mean by item.

    I just showed you how to set the height of the stackpanel.

    Bind it.

     <StackPanel Orientation="Horizontal"
                 Height="{Binding MyHeight, Mode=TwoWay}"

    That's the effective height of the stackpanel, it would have to be unset for it to be able to grow to content.

    But - that is the height of the thing in a node. Do not confuse that with the headeredcontentcontrol.

    If you mean treeviewitem by item then that's not just that node, it's the node and any children you expand.


    Hope that helps.

    Technet articles: WPF: Layout Lab; All my Technet Articles

    • Proposed as answer by DotNet Wang Thursday, May 5, 2016 7:16 AM
    • Marked as answer by Xavier Xie-MSFT Thursday, May 5, 2016 12:14 PM
    Friday, April 29, 2016 8:31 AM

All replies

  • A treeviewitem is a headereditemscontrol. The default stuff in a node is the header AND an itemscontrol for the children.

    You should use a datatemplate / hierarchicaldatatemplate rather that setting the headertemplate like that.

    For example:

            <TreeView Name="trvFamilies" ItemsSource="{Binding Families}" Grid.Row="1" Grid.ColumnSpan="2">
                <TreeView.Resources>
                    <HierarchicalDataTemplate DataType="{x:Type local:Family}" ItemsSource="{Binding Members}">
                        <StackPanel Orientation="Horizontal"
                                    Height="32"
                                    >
                            <Label VerticalAlignment="Center" FontFamily="WingDings" Content="1"/>
                            <TextBlock Text="{Binding Name}" />
                        </StackPanel>
                    </HierarchicalDataTemplate>
                    <DataTemplate DataType="{x:Type local:FamilyMember}">
                        <StackPanel Orientation="Horizontal"
                                    Height="32"
                                    x:Name="sp">
                            <TextBlock Tag="{Binding DataContext.Name, 
                                RelativeSource={RelativeSource AncestorType=TreeViewItem , AncestorLevel=2}
                                }" 
                                Text="{Binding Name}" >
                            </TextBlock>
                            <TextBlock Text=" (" Foreground="Green" />
                            <TextBlock Text="{Binding Age}" Foreground="Green" />
                            <TextBlock Text=" years)" Foreground="Green" />
                        </StackPanel>
                    </DataTemplate>
                </TreeView.Resources>
            </TreeView>
    Here, each item will be 32 height.


    Hope that helps.

    Technet articles: WPF: Layout Lab; All my Technet Articles

    • Proposed as answer by David Roller Thursday, April 28, 2016 6:43 PM
    • Marked as answer by Xavier Xie-MSFT Thursday, May 5, 2016 12:14 PM
    Thursday, April 28, 2016 5:54 PM
  • get: ActualHeight
    Thursday, April 28, 2016 5:55 PM
  • As I explained the actualheight of a treeviewitem is very unlikely to be what you want.

    Assuming there is any point in this being a treeview rather than a listbox, there will be children involved.

    Set or get the actualheight of whatever you template each of your objects as.

    In the case of my markup above, that would be the stackpanel.

     <StackPanel Orientation="Horizontal"
                 Height="32"
                 x:Name="sp">
    If you set Height and it's not measure - arranged then actualheight could still well be NAN and you should use Height.


    Hope that helps.

    Technet articles: WPF: Layout Lab; All my Technet Articles

    Thursday, April 28, 2016 6:11 PM
  • I forgot to mention binding.

    You should have an observablecollection<t> you're binding to the itemssource of the treeview.

    And t will presumably have a property which is also an observablecollection of some sort. For the children.

    In t you can expose a public property, call that MyHeight.

    You then bind that:

     <StackPanel Orientation="Horizontal"
                 Height="{Binding MyHeight, Mode=TwoWay}"

    t should implement inotifypropertychanged and raise property changed when MyHeight is set.

    You can then set MyHeight and the view will respond.

    You can read MyHeight and it will be the current height ( although you set it so you already know what it is ).


    Hope that helps.

    Technet articles: WPF: Layout Lab; All my Technet Articles

    Thursday, April 28, 2016 7:05 PM
  • >    <HierarchicalDataTemplate DataType="{x:Type local:Family}" ItemsSource="{Binding Members}">
    >           <DataTemplate DataType="{x:Type local:FamilyMember}">

    What is local:Family and local:FamilyMember ?

    Thursday, April 28, 2016 7:11 PM
  • They're types.

        public class Family
        {
            public Family()
            {
                this.Members = new ObservableCollection<FamilyMember>();
            }
            public string Name { get; set; }
            public ObservableCollection<FamilyMember> Members { get; set; }
        }
    
        public class FamilyMember
        {
            public string Name { get; set; }
            public int Age { get; set; }
        }

    and local is the xmlns reference to the project.

    <Window x:Class="wpf_TreeView.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:wpf_TreeView"

    That's the same markup and code  I posted in your other thread.

    Using datatype= on a datatemplate tells wpf to template an object matching that type using the template provided.


    Hope that helps.

    Technet articles: WPF: Layout Lab; All my Technet Articles

    • Proposed as answer by DotNet Wang Thursday, May 5, 2016 7:16 AM
    • Marked as answer by Xavier Xie-MSFT Thursday, May 5, 2016 12:14 PM
    Thursday, April 28, 2016 7:17 PM
  • Is possible to change height of stackpanel of item but still item.height=NaN,

    How read height of this stackpanel?

    Friday, April 29, 2016 6:09 AM
  • It depends what you mean by item.

    I just showed you how to set the height of the stackpanel.

    Bind it.

     <StackPanel Orientation="Horizontal"
                 Height="{Binding MyHeight, Mode=TwoWay}"

    That's the effective height of the stackpanel, it would have to be unset for it to be able to grow to content.

    But - that is the height of the thing in a node. Do not confuse that with the headeredcontentcontrol.

    If you mean treeviewitem by item then that's not just that node, it's the node and any children you expand.


    Hope that helps.

    Technet articles: WPF: Layout Lab; All my Technet Articles

    • Proposed as answer by DotNet Wang Thursday, May 5, 2016 7:16 AM
    • Marked as answer by Xavier Xie-MSFT Thursday, May 5, 2016 12:14 PM
    Friday, April 29, 2016 8:31 AM
  • double.NaN is in fact the expected value of the Height property when you haven't specified an explicit height for the control.

    You could use the ActualHeight property to get the actual rendered height of the control:

    double height = stackPanel1.ActualHeight;

    Hope that helps.

    Please remember to close your threads by marking helpful posts as answer and then start a new thread if you have a new question. Please don't ask several questions in the same thread.

    Sunday, May 1, 2016 10:36 AM