none
TreeView and selected item

    Question

  • Hi, I'm new to WPF. I managed to build a tree view from xml like this:
    A  
    |_ A1  
    |_ A2  
       |_A21  
       |_A22  
    B  
    |_ B1  
    |_ B2 


    <XmlDataProvider  
      x:Key="MyConfig1" 
      Source="Config/c1.xml" 
      XPath="/MyConfig/*" 
    /> 
     
    <HierarchicalDataTemplate DataType="MyItem" ItemsSource ="{Binding XPath=child::*}">  
      <TextBlock  
        Text="{Binding XPath=@Name}" 
        ToolTip="{Binding XPath=@Name}" 
        Tag="{Binding XPath=@Path}" 
      /> 
    </HierarchicalDataTemplate> 


    and then set the style to expand and highlight selected:
    <Style x:Key="MyTree" TargetType="TreeView">     
      <Style.Resources>    
        <Style TargetType="{x:Type TreeViewItem}">     
          <Setter Property="IsExpanded" Value="True" />    
          <Style.Triggers>    
            <Trigger Property="IsSelected" Value="True">     
              <Setter Property="FontWeight" Value="Bold" />    
            </Trigger>    
          </Style.Triggers>    
        </Style>    
      </Style.Resources>    
    </Style>    
    (...)
    <TreeView  
      Name="treeViewMain" Style="{StaticResource MyTree}" 
      DataContext="{StaticResource MyConfig1}" ItemsSource="{Binding}" 
      TreeViewItem.Selected="Nav_Selected">  
    </TreeView> 


    But I have some issues:
    1. If I select for example A2, it also set A21 and A22 bold. How to apply style to only item I've selected?
    2. I pass the attribute @Path as TextBlock Tag. How to get that value when select a TreeViewItem. In My function Nav_Selected, I tried ((FrameworkElement)sender).Tag but got null.

    Thanks in advance.
    Monday, January 19, 2009 3:52 PM

Answers

  • Hi,

     

    Bigsby has provided a good approach, for some detailed supplement, the following includes a small repro based on your explaination.

     

    -->1. If I select for example A2, it also set A21 and A22 bold. How to apply style to only item I've selected?

     

    In most circumstances, we can set ItemContainerStyle property of TreeView for TreeViewItem’s style instead of setting it in TreeView’s Resource section. By doing this, we can clearly see the style for each items in TreeView and ignore some confusion.

     

    -->2. I pass the attribute @Path as TextBlock Tag. How to get that value when select a TreeViewItem. In My function Nav_Selected, I tried ((FrameworkElement)sender).Tag but got null.

     

    Actually, in the Selected event handler of TreeViewItem, the sender is of type TreeView.It does not make much sense that you cast a TreeView to a FrameworkElement type in this scenario.As a result, the Tag of (sender as FrameworkElement) must be null due to you have not set any value for the TreeView. As Bigsby said above, you could use the FindName method to find the Controls inside DataTemplate.

     

    XAML code:

    <Window x:Class="WpfTreeView.Window1"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:local="clr-namespace:WpfTreeView"

        Title="Window1" Height="300" Width="300">

        <Window.Resources>

            <XmlDataProvider x:Key="treeData" XPath="*">

                <x:XData>

                    <Items Name="Items" xmlns="">

                        <Item1/>

                        <Item2>

                            <Item21>

                                <Item211/>

                                <Item212/>

                            </Item21>

                            <Item22/>

                        </Item2>

                        <Item3>

                            <Item31/>

                            <Item32/>

                        </Item3>

                        <Item4>

                            <Item41/>

                            <Item42/>

                        </Item4>

                    </Items>

                </x:XData>

            </XmlDataProvider>

            <!--HierarchicalDataTemplate-->

            <HierarchicalDataTemplate

                ItemsSource="{Binding XPath=child::*}"

                x:Key="template">

                <TextBlock Name="textBlock"

                           Text="{Binding Name}"

                           ToolTip="{Binding Name}" 

                           Tag="{Binding Name}" 

                           />

            </HierarchicalDataTemplate>

            <!--TreeView Style-->

        </Window.Resources>

        <StackPanel Orientation="Horizontal">

            <TreeView  Name="treeview"

                       ItemTemplate="{StaticResource template}"

                       TreeViewItem.Selected="OnTreeViewItemSelected"

                       ItemsSource="{Binding Source={StaticResource treeData}}">

                <TreeView.ItemContainerStyle>

                    <Style TargetType="{x:Type TreeViewItem}">

                        <Setter Property="IsExpanded" Value="True" />

                        <Setter Property="FontWeight" Value="Normal" />

                        <Style.Triggers>

                            <Trigger Property="IsSelected" Value="True">

                                <Setter Property="FontWeight" Value="Bold" />

                            </Trigger>

                        </Style.Triggers>

                    </Style>

                </TreeView.ItemContainerStyle>

            </TreeView>

        </StackPanel>

    </Window>

     

    In the code behind:

     

    namespace WpfTreeView

    {

        public partial class Window1 : Window

        {

            public Window1()

            {

                InitializeComponent();

            }

            private void OnTreeViewItemSelected(object sender, RoutedEventArgs e)

            {

                TreeViewItem item = e.OriginalSource as TreeViewItem;

                TextBlock  textBlock = GetvisualChildByName(item, "textBlock") as TextBlock;

                string line = System.Environment.NewLine;

                string text=textBlock.Text ;

                string toolTip=textBlock.ToolTip.ToString ();

                string  tag=textBlock.Tag.ToString ();

                MessageBox.Show("Text: " + text +line+ "ToolTip: " + toolTip + line + "Tag: " + tag);

            }

            public static Visual GetvisualChildByName(Visual element, string name)

            {

                if (element == null) return null;

                if (element is FrameworkElement && (element as FrameworkElement).Name == name) return element;

                Visual result = null;

                if (element is FrameworkElement)

                {

                    (element as FrameworkElement).ApplyTemplate();

                }

                for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)

                {

                    Visual visual = VisualTreeHelper.GetChild(element, i) as Visual;

                    result = GetvisualChildByName(visual, name);

                    if (result != null)

                        break;

                }

                return result;

            }

        }

    }

     

    Hope this helps.

     

    Thanks.

     

    • Marked as answer by Replika Wednesday, January 21, 2009 4:00 PM
    Wednesday, January 21, 2009 7:07 AM
  • 1. I'm not totally sure and will have to check but, as you are setting the value for a DependencyProperty, meaning a property that spread to visual children, and not setting that same property to the non-selected Items, the property is passed. I think you'll be ok if you have a setter setting FontWeight to Normal. On that Style.

    2. You'll have to name the TextBlock control and use FrameworkTemplate.FindName method to get to the TextBlock object and then get the property.

    Bigsby, Lisboa, Portugal
    • Marked as answer by Replika Wednesday, January 21, 2009 4:01 PM
    Monday, January 19, 2009 4:26 PM

All replies

  • 1. I'm not totally sure and will have to check but, as you are setting the value for a DependencyProperty, meaning a property that spread to visual children, and not setting that same property to the non-selected Items, the property is passed. I think you'll be ok if you have a setter setting FontWeight to Normal. On that Style.

    2. You'll have to name the TextBlock control and use FrameworkTemplate.FindName method to get to the TextBlock object and then get the property.

    Bigsby, Lisboa, Portugal
    • Marked as answer by Replika Wednesday, January 21, 2009 4:01 PM
    Monday, January 19, 2009 4:26 PM
  • Thanks for you answer. I'm building a navigation that read data from xml. The xml contains Item name and Page name that it points to. And I still could not highlight and take the value of each selected item.
    Do you have a suggestion?
    Tuesday, January 20, 2009 2:42 PM
  • Hi,

     

    Bigsby has provided a good approach, for some detailed supplement, the following includes a small repro based on your explaination.

     

    -->1. If I select for example A2, it also set A21 and A22 bold. How to apply style to only item I've selected?

     

    In most circumstances, we can set ItemContainerStyle property of TreeView for TreeViewItem’s style instead of setting it in TreeView’s Resource section. By doing this, we can clearly see the style for each items in TreeView and ignore some confusion.

     

    -->2. I pass the attribute @Path as TextBlock Tag. How to get that value when select a TreeViewItem. In My function Nav_Selected, I tried ((FrameworkElement)sender).Tag but got null.

     

    Actually, in the Selected event handler of TreeViewItem, the sender is of type TreeView.It does not make much sense that you cast a TreeView to a FrameworkElement type in this scenario.As a result, the Tag of (sender as FrameworkElement) must be null due to you have not set any value for the TreeView. As Bigsby said above, you could use the FindName method to find the Controls inside DataTemplate.

     

    XAML code:

    <Window x:Class="WpfTreeView.Window1"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:local="clr-namespace:WpfTreeView"

        Title="Window1" Height="300" Width="300">

        <Window.Resources>

            <XmlDataProvider x:Key="treeData" XPath="*">

                <x:XData>

                    <Items Name="Items" xmlns="">

                        <Item1/>

                        <Item2>

                            <Item21>

                                <Item211/>

                                <Item212/>

                            </Item21>

                            <Item22/>

                        </Item2>

                        <Item3>

                            <Item31/>

                            <Item32/>

                        </Item3>

                        <Item4>

                            <Item41/>

                            <Item42/>

                        </Item4>

                    </Items>

                </x:XData>

            </XmlDataProvider>

            <!--HierarchicalDataTemplate-->

            <HierarchicalDataTemplate

                ItemsSource="{Binding XPath=child::*}"

                x:Key="template">

                <TextBlock Name="textBlock"

                           Text="{Binding Name}"

                           ToolTip="{Binding Name}" 

                           Tag="{Binding Name}" 

                           />

            </HierarchicalDataTemplate>

            <!--TreeView Style-->

        </Window.Resources>

        <StackPanel Orientation="Horizontal">

            <TreeView  Name="treeview"

                       ItemTemplate="{StaticResource template}"

                       TreeViewItem.Selected="OnTreeViewItemSelected"

                       ItemsSource="{Binding Source={StaticResource treeData}}">

                <TreeView.ItemContainerStyle>

                    <Style TargetType="{x:Type TreeViewItem}">

                        <Setter Property="IsExpanded" Value="True" />

                        <Setter Property="FontWeight" Value="Normal" />

                        <Style.Triggers>

                            <Trigger Property="IsSelected" Value="True">

                                <Setter Property="FontWeight" Value="Bold" />

                            </Trigger>

                        </Style.Triggers>

                    </Style>

                </TreeView.ItemContainerStyle>

            </TreeView>

        </StackPanel>

    </Window>

     

    In the code behind:

     

    namespace WpfTreeView

    {

        public partial class Window1 : Window

        {

            public Window1()

            {

                InitializeComponent();

            }

            private void OnTreeViewItemSelected(object sender, RoutedEventArgs e)

            {

                TreeViewItem item = e.OriginalSource as TreeViewItem;

                TextBlock  textBlock = GetvisualChildByName(item, "textBlock") as TextBlock;

                string line = System.Environment.NewLine;

                string text=textBlock.Text ;

                string toolTip=textBlock.ToolTip.ToString ();

                string  tag=textBlock.Tag.ToString ();

                MessageBox.Show("Text: " + text +line+ "ToolTip: " + toolTip + line + "Tag: " + tag);

            }

            public static Visual GetvisualChildByName(Visual element, string name)

            {

                if (element == null) return null;

                if (element is FrameworkElement && (element as FrameworkElement).Name == name) return element;

                Visual result = null;

                if (element is FrameworkElement)

                {

                    (element as FrameworkElement).ApplyTemplate();

                }

                for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)

                {

                    Visual visual = VisualTreeHelper.GetChild(element, i) as Visual;

                    result = GetvisualChildByName(visual, name);

                    if (result != null)

                        break;

                }

                return result;

            }

        }

    }

     

    Hope this helps.

     

    Thanks.

     

    • Marked as answer by Replika Wednesday, January 21, 2009 4:00 PM
    Wednesday, January 21, 2009 7:07 AM