- Details
- Written by: Stanko Milosev
- Category: WPF
- Hits: 7469
One more article in my list of articles about tree view expanding.
This time I will use story board from code behind.
XAML:
<Window x:Class="TreeViewAutoExpand.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewModel="clr-namespace:TreeViewAutoExpand.ViewModel"
xmlns:model="clr-namespace:TreeViewAutoExpand.Model"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.Resources>
<viewModel:TreeViewAutoExpandViewModel x:Key="TreeViewAutoExpandViewModel" />
</Grid.Resources>
<TreeView x:Name="MyTreeView" DataContext="{StaticResource TreeViewAutoExpandViewModel}" ItemsSource="{Binding TreeViewAutoExpandItems}" Loaded="MyTreeView_Loaded">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}" DataType="{x:Type model:TreeViewAutoExpandModel}">
<TreeViewItem x:Name="myTreeViewItem" Header="{Binding Name}"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
</Window>
Code:
using System.Windows;
namespace TreeViewAutoExpand
{
using System;
using System.Windows.Controls;
using System.Windows.Media.Animation;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void MyTreeView_Loaded(object sender, RoutedEventArgs e)
{
BooleanAnimationUsingKeyFrames bukf = new BooleanAnimationUsingKeyFrames();
Storyboard.SetTargetProperty(bukf, new PropertyPath(TreeViewItem.IsExpandedProperty));
Storyboard.SetTarget(bukf, MyTreeView);
foreach (object item in MyTreeView.Items)
{
TreeViewItem currentContainer = (TreeViewItem)MyTreeView.ItemContainerGenerator.ContainerFromItem(item);
if (currentContainer != null)
{
Storyboard.SetTarget(bukf, currentContainer);
}
}
bukf.KeyFrames.Add(new DiscreteBooleanKeyFrame(false, KeyTime.FromTimeSpan(TimeSpan.FromSeconds(0.0))));
bukf.KeyFrames.Add(new DiscreteBooleanKeyFrame(true, KeyTime.FromTimeSpan(TimeSpan.FromSeconds(2.0))));
Storyboard myStoryboard = new Storyboard();
myStoryboard.Children.Add(bukf);
myStoryboard.Begin();
}
}
}
Point of interest:
foreach (object item in MyTreeView.Items)
{
TreeViewItem currentContainer = (TreeViewItem)MyTreeView.ItemContainerGenerator.ContainerFromItem(item);
if (currentContainer != null)
{
Storyboard.SetTarget(bukf, currentContainer);
}
}
This code I needed since I didn't know how to access tree view items from code behind.
Example download from here.
- Details
- Written by: Stanko Milosev
- Category: WPF
- Hits: 5563
XAML:
<Window x:Class="TreeViewAutoExpand.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewModel="clr-namespace:TreeViewAutoExpand.ViewModel"
xmlns:model="clr-namespace:TreeViewAutoExpand.Model"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.Resources>
<viewModel:TreeViewAutoExpandViewModel x:Key="TreeViewAutoExpandViewModel" />
</Grid.Resources>
<TreeView x:Name="MyTreeView" DataContext="{StaticResource TreeViewAutoExpandViewModel}" ItemsSource="{Binding TreeViewAutoExpandItems}" Loaded="MyTreeView_Loaded">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}" DataType="{x:Type model:TreeViewAutoExpandModel}">
<TreeViewItem x:Name="myTreeViewItem" Header="{Binding Name}"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
</Window>
Thing to notice:
<TreeView x:Name="MyTreeView" DataContext="{StaticResource TreeViewAutoExpandViewModel}" ItemsSource="{Binding TreeViewAutoExpandItems}" Loaded="MyTreeView_Loaded">
Code:
using System.Windows;
namespace TreeViewAutoExpand
{
using System.Windows.Controls;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void ShowSelectedThing(ItemsControl parentContainer)
{
// check current level of tree
foreach (object item in parentContainer.Items)
{
TreeViewItem currentContainer = (TreeViewItem)parentContainer.ItemContainerGenerator.ContainerFromItem(item);
if (currentContainer != null)
{
currentContainer.IsExpanded = true;
}
}
}
private void MyTreeView_Loaded(object sender, RoutedEventArgs e)
{
ShowSelectedThing(MyTreeView);
}
}
}
Example you can download from here.
- Details
- Written by: Stanko Milosev
- Category: WPF
- Hits: 6574
To write this article I was using this answer.
XAML:
<Window x:Class="TreeViewMouseOverExpand.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewModel="clr-namespace:TreeViewMouseOverExpand.ViewModel"
xmlns:treeViewModel="clr-namespace:TreeViewMouseOverExpand.Model"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.Resources>
<viewModel:TreeViewMouseOverExpandViewModel x:Key="TreeViewMouseOverExpandViewModel" />
</Grid.Resources>
<TreeView DataContext="{StaticResource TreeViewMouseOverExpandViewModel}" ItemsSource="{Binding TreeViewMouseOverExpandItems}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}" DataType="{x:Type treeViewModel:TreeViewMouseOverExpandModel}">
<TreeViewItem Header="{Binding Name}"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="IsExpanded" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
</Grid>
</Window>
Thing which you have to notice is:
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="IsExpanded" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>
Here you can download example.
- Details
- Written by: Stanko Milosev
- Category: WPF
- Hits: 7061
Now idea is to expand tree items after some period of time.
XAML:
<Window x:Class="TreeViewMouseOverExpand.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewModel="clr-namespace:TreeViewMouseOverExpand.ViewModel"
xmlns:treeViewModel="clr-namespace:TreeViewMouseOverExpand.Model"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.Resources>
<viewModel:TreeViewMouseOverExpandViewModel x:Key="TreeViewMouseOverExpandViewModel" />
</Grid.Resources>
<TreeView DataContext="{StaticResource TreeViewMouseOverExpandViewModel}" ItemsSource="{Binding TreeViewMouseOverExpandItems}">
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Style.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames
Duration="00:00:01"
Storyboard.TargetProperty="(TreeViewItem.IsExpanded)">
<DiscreteBooleanKeyFrame Value="True" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}" DataType="{x:Type treeViewModel:TreeViewMouseOverExpandModel}">
<TreeViewItem Header="{Binding Name}">
</TreeViewItem>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
</Window>
Example download from here.
---
Problem with above example is that after executing event trigger you will not be able to change any property (that means that expand / collapse will not work anymore). Solution is in FillBehavior="Stop" (see How to: Set a Property After Animating It with a Storyboard), but, I wouldn't write this article if there is no at least one "but" :), I didn't find proper solution, until now, problem is that if you FillBehavior="Stop" in MouseEnter then trigger will not work at all... if you implement MouseLeave trigger with FillBehavior="Stop", then it will partly work with strange behavior...
In my case, for our product I implemented TreeViewItem.PreviewDragEnter (without FillBehavior="Stop"), and then TreeViewItem.MouseLeave with FillBehavior="Stop", so I have two different triggers on which I could respond... but for MouseEnter / MouseLeave I don't have clear idea how to do it without some hacking in code behind...