Treeview in wpf - wpf

im trying to bind a ItemsControl to use as an Repeater (Asp.net) inside a static treeview in WPF.
Code.
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<TreeView Margin="10,10,0,13" Name="TreeView1" HorizontalAlignment="Left" VerticalAlignment="Top" Width="194" Height="200" >
<TreeViewItem Header="Cold Drinks" IsExpanded="true">
<TreeViewItem Header="Coke" IsExpanded="true">
<ItemsControl Name="list" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<TreeViewItem Header="{Binding}"></TreeViewItem>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</TreeViewItem>
<TreeViewItem Header="Orange Juice"></TreeViewItem>
</TreeViewItem>
</TreeView>
</StackPanel>
</Window>
C#
list.ItemsSource = new List<string> { "Coke1", "Coke2", "Coke3" };
This results in 3 subitems that seems to be i a group, if i select one i select all.
Anyone?
Thanks,
Magnus

Set the ItemsSource-property of the TreeViewItem to your list. This will get you what you expect.
In the following code, I have set the name of your list to the TreeViewItem (as a short hack) for demonstration purposes. So your code will attach the list to the ItemsSource of the TreeViewItem.
<TreeViewItem Header="Cold Drinks" IsExpanded="true">
<TreeViewItem Header="Coke" IsExpanded="true" Name="list">
</TreeViewItem>
<TreeViewItem Header="Orange Juice">
</TreeViewItem>
</TreeViewItem>

Related

Element Binding To TreeView SelectedItem Where TreeViewItem has ItemsSource

I have the following UserControl:
<UserControl x:Class="ConcreteAnalyzer.Views.CenterSectionPropertiesView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:c="clr-namespace:ConcreteAnalyzer.Converters"
xmlns:local="clr-namespace:ConcreteAnalyzer.Views"
xmlns:vm="clr-namespace:ConcreteAnalyzer.ViewModels.CenterSection"
mc:Ignorable="d">
<UserControl.Resources >
<c:DebugConverter x:Key="DebugConverter"/>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="8"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<TreeView Grid.Row="0" x:Name="CenterSectionTree">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type vm:PanViewModel}">
<TreeViewItem Header="Pan"/>
</HierarchicalDataTemplate>
</TreeView.Resources>
<TreeViewItem Header="Center Section" DataContext="{Binding CenterSection}">
<TreeViewItem Header="Front" DataContext="{Binding XPositive}" ItemsSource="{Binding Pans, Converter={StaticResource DebugConverter}}"/>
<TreeViewItem Header="Back" DataContext="{Binding XNegative}" ItemsSource="{Binding Pans}"/>
<TreeViewItem Header="Left" DataContext="{Binding YPositive}" ItemsSource="{Binding Pans}"/>
<TreeViewItem Header="Rigth" DataContext="{Binding YNegative}" ItemsSource="{Binding Pans}"/>
</TreeViewItem>
</TreeView>
<GridSplitter Grid.Row="1" Height="8" ResizeDirection="Rows" HorizontalAlignment="Stretch" ResizeBehavior="PreviousAndNext">
<GridSplitter.Template>
<ControlTemplate TargetType="{x:Type GridSplitter}">
<Grid>
<Button Content="⁞" Background="Transparent" Foreground="White"/>
<Rectangle Fill="{StaticResource TurqoiseBrush}"/>
</Grid>
</ControlTemplate>
</GridSplitter.Template>
</GridSplitter >
<ContentControl Content="{Binding SelectedItem.DataContext, ElementName=CenterSectionTree, Converter={StaticResource DebugConverter}}" Grid.Row="2">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type vm:CenterSectionViewModel}">
<TextBlock Text="Center Section"/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:WallViewModel}">
<TextBlock Text="Wall"/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:PanViewModel}">
<TextBlock Text="Pan"/>
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
</Grid>
This works just fine for the Treeview items that are hard-coded but if I select one of the pans, the ElementBinding does not connect. I could change the treeview to use HiearchicalDataTemplate, but to do that I think I have to create dummy collections to bind to at each level as well as add a property to the walls so that I can tell which wall is which. Creating all that dummy info just to make the treeview work has some code smell to me.
Any thoughts on the best way to get this to work?
edit:
The reason it's not working is because when the hard-coded treeview items are selected the databinding points at the TreeViewItem itself and so I was binding to the SelectedItem.DataContext. When you select a Pan, the SelectedItem is the PanViewModel, not the TreeViewItem.
If I Try simply binding to the SelectedItem, the hard-coded TreeViewItems will not work because it tries to inject the TreeViewItem itself into a ContentControl, which throws an exception.
Binding to the SelectedItem.DataContext won't work because the PanViewModel doesn't have a DataContext. I'm still not seeing an elegant solution to this.

View Controls show/hide WPF MVVM

I have a View (in MVVM) which have some controls including a treeview. A ViewModel which is the datacontext and a Model, everything is working fine till now. **I have two cases:
**
I want my View to show a ContextMenu against Treeview items.
The other case, it should not show a ContextMenu against the Treeview items
Is this possible with one View or there should be two different Views for this purpose, for my personal work it would be better if I have one View.
The VM and model are very simple just having the binded properties of the View.
View.xaml
<UserControl x:Class="SPM.SystemExplorer.View.SystemExplorerView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:SPM.SystemExplorer.View"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
xmlns:viewModel="clr-namespace:SPM.SystemExplorer.ViewModel"
xmlns:classes="clr-namespace:SPM.SystemExplorer.Classes">
<UserControl.DataContext>
<viewModel:SystemExplorerViewVM></viewModel:SystemExplorerViewVM>
</UserControl.DataContext>
<Grid>
<StackPanel>
<Label Content="{Binding Test}"></Label>
<TreeView Grid.Row="1" ItemsSource="{Binding SystemProjects}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type classes:SystemProject}" ItemsSource="{Binding ParticipantProjects}">
<StackPanel Orientation="Horizontal">
<TreeViewItem Header="{Binding NameOfSystemProject}"></TreeViewItem>
<TreeViewItem Header="{Binding AuthorOfSystemProject}"></TreeViewItem>
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type classes:ParticipantProject}">
<StackPanel Orientation="Horizontal">
<TreeViewItem Header="{Binding NameOfParticipantProject}"></TreeViewItem>
<TreeViewItem Header="{Binding AuthorOfParticipantProject}"></TreeViewItem>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
</StackPanel>
</Grid>
You could add a property (ShowContextMenu) to your SystemExplorerViewVM class that you set to true/false depending on whether you want to display the ContextMenu. You could then use a Style with a DataTrigger in your XAML:
<TreeView Grid.Row="1" ItemsSource="{Binding SystemProjects}">
<TreeView.Resources>
<ContextMenu x:Key="cm">
<MenuItem Header="1" />
<MenuItem Header="2" />
</ContextMenu>
<Style TargetType="TreeViewItem">
<Style.Triggers>
<DataTrigger Binding="{Binding DataContext.ShowContextMenu, RelativeSource={RelativeSource AncestorType=UserControl}}" Value="True">
<Setter Property="ContextMenu" Value="{StaticResource cm}" />
</DataTrigger>
</Style.Triggers>
</Style>
<HierarchicalDataTemplate DataType="{x:Type classes:SystemProject}" ItemsSource="{Binding ParticipantProjects}">
<StackPanel Orientation="Horizontal">
<TreeViewItem Header="{Binding NameOfSystemProject}"></TreeViewItem>
<TreeViewItem Header="{Binding AuthorOfSystemProject}"></TreeViewItem>
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type classes:ParticipantProject}">
<StackPanel Orientation="Horizontal">
<TreeViewItem Header="{Binding NameOfParticipantProject}"></TreeViewItem>
<TreeViewItem Header="{Binding AuthorOfParticipantProject}"></TreeViewItem>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView>

How to bind a resource to a flowdocumentreader from a treeview with only XAML?

This time I am working on a help-window mini-application (to include in the other project, the imageediting application).
I have a grid with two columns and a gridsplitter inbetween. On the left I have a treeview with several nodes (set in XAML) and on the right a flowdocumentreader.
I have about 10 resourcedictionaries where I keep my documents, one for each node, that I want to display in my flowdocumentreader. I actually have no idea how to bind this! Anybody have an idea how I can do this? My code so far (only one resourcedictionary added)
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary x:Name="About" Source="About.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="500"/>
</Grid.ColumnDefinitions>
<GridSplitter HorizontalAlignment="Right"
VerticalAlignment="Stretch"
Grid.Column="1" ResizeBehavior="PreviousAndNext" ResizeDirection="Columns"
Width="5" Background="#FFBCBCBC"/>
<TreeView Width="250" Grid.Column="0" FontFamily="Segoe UI" FontSize="16">
<TreeViewItem Header="Help">
<TreeViewItem Header="About the application"></TreeViewItem>
<TreeViewItem Header="Getting started"></TreeViewItem>
<TreeViewItem Header="Images from Flickr"></TreeViewItem>
<TreeViewItem Header="Images from the computer"></TreeViewItem>
<TreeViewItem Header="Images from the browser"></TreeViewItem>
<TreeViewItem Header="Editing">
<TreeViewItem Header="Open and Save"></TreeViewItem>
<TreeViewItem Header="Uploading"></TreeViewItem>
<TreeViewItem Header="Crop"></TreeViewItem>
<TreeViewItem Header="Resize"></TreeViewItem>
<TreeViewItem Header="Filters"></TreeViewItem>
<TreeViewItem Header="Adding text"></TreeViewItem>
<TreeViewItem Header="Remove red eyes"></TreeViewItem>
</TreeViewItem>
</TreeViewItem>
</TreeView>
<FlowDocumentReader Grid.Column="2" >
</FlowDocumentReader>
</Grid>
You could use the Tag property of the nodes to define a string value to be loaded.
Then do a binding on the selected Node's Tag.
If you then use a converter you can load your document content from file/res.Dict or whatever:
<TreeView x:Name="documentTreeView" Width="250" Grid.Column="0" FontFamily="Segoe UI" FontSize="16">
<TreeViewItem Header="Help">
<TreeViewItem
Header="About the application"
Tag="ResDict1.xaml"></TreeViewItem>
....
<FlowDocumentReader Document="{Binding ElementName=documentTreeView, Path=SelectedItem.Tag, Converter={StaticResource stringToFlowDocumentConverter}}" Grid.Column="2" />

2 identical Controls in the same Grid ? (WPF/xaml)

Here is a simple code that exposes my problem :
<Grid>
<TreeView Name="myTreeViewEvent" >
<TreeViewItem Header="Employee1"/>
</TreeView>
<TreeView Name="myTreeViewEvent2" >
<TreeViewItem Header="Employee2"/>
</TreeView>
</Grid>
The thing is that my 2nd Treeview "overwrites" the 1st one...
Is there a way to change the behaviour so that the 2nd Treeview is "added" to the 1st one ?
(nb : no, I can't put them in the same Treeview cause in my "real" code, I got 2 different Treeviews that I CAN'T merge... and I gotta display them in the same grid !)
Try this
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TreeView Name="myTreeViewEvent" >
<TreeViewItem Header="Employee1"/>
</TreeView>
<TreeView Grid.Row="1" Name="myTreeViewEvent2" >
<TreeViewItem Header="Employee2"/>
</TreeView>
</Grid>
EDIT
Then what prevents you from using this approach?
<Grid>
<StackPanel>
<TreeView Name="myTreeViewEvent">
<TreeViewItem Header="Employee1"/>
</TreeView>
<TreeView Name="myTreeViewEvent2">
<TreeViewItem Header="Employee2"/>
</TreeView>
</StackPanel>
</Grid>
In this case there is no strict division. The items will strech up.

Enable scroll for WPF Treeview

Can anybody help me out with how to enable a treeview to scroll? There must be a simple way but I can't make it work in my code. After multiple failed tries, I currently have something like this:
<ScrollViewer CanContentScroll="True">
<TreeView ...>
</TreeView>
</ScrollViewer>
I do see an 'disabled' scrollbar, but when the notes of the treeview are larger than the screen height, no scrolling is activated.
The TreeView control itself includes a ScrollViewer in its template. You should be able to just use a TreeView inside an appropriate host (not a StackPanel!).
The TreeView contains a ScrollViewer, but as #Carlo said, the TreeView or its container needs to have a height. Alternatively, the TreeView should be hosted in a container that doesn't give infinite height to its children (i.e. a StackPanel which I think was what #Kent was meaning). So place it inside a Grid, no need to give the Grid or the TreeView an explicit height and you should get the scrollbars.
Do you have a height explicitly set on your window? If you want to see the scrollbar something must define the height of the TreeView or its container, otherwise it won't know when it needs to show the scrollbar.
Example:
<Window x:Class="StackOverflowTests.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" x:Name="window1" Height="300" Width="300">
<Grid>
<TreeView Name="treeView1" Height="150" VerticalAlignment="Top">
<TreeViewItem Header="Root" IsExpanded="True">
<TreeViewItem Header="Item 1"></TreeViewItem>
<TreeViewItem Header="Item 2"></TreeViewItem>
<TreeViewItem Header="Item 3"></TreeViewItem>
<TreeViewItem Header="Item 4"></TreeViewItem>
<TreeViewItem Header="Item 5"></TreeViewItem>
<TreeViewItem Header="Item 6"></TreeViewItem>
<TreeViewItem Header="Item 7"></TreeViewItem>
<TreeViewItem Header="Item 8"></TreeViewItem>
<TreeViewItem Header="Item 9"></TreeViewItem>
<TreeViewItem Header="Item 10"></TreeViewItem>
<TreeViewItem Header="Item 11"></TreeViewItem>
<TreeViewItem Header="Item 12"></TreeViewItem>
<TreeViewItem Header="Item 13"></TreeViewItem>
<TreeViewItem Header="Item 14"></TreeViewItem>
<TreeViewItem Header="Item 15"></TreeViewItem>
<TreeViewItem Header="Item 16"></TreeViewItem>
<TreeViewItem Header="Item 17"></TreeViewItem>
<TreeViewItem Header="Item 18"></TreeViewItem>
<TreeViewItem Header="Item 19"></TreeViewItem>
<TreeViewItem Header="Item 20"></TreeViewItem>
<TreeViewItem Header="Item 21"></TreeViewItem>
<TreeViewItem Header="Item 22"></TreeViewItem>
<TreeViewItem Header="Item 23"></TreeViewItem>
<TreeViewItem Header="Item 24"></TreeViewItem>
<TreeViewItem Header="Item 24"></TreeViewItem>
</TreeViewItem>
</TreeView>
</Grid>
</Window>
It's a simply a matter of giving the TreeView a fixed Height and Width. And maybe put it in a border. Also, i do have a MaxWidth on my items' content. For example the following is in my main window under two stack panels and it works (I'm using MahApps Metro controls):
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Border BorderThickness="2" BorderBrush="DarkGoldenrod" Margin="4">
<TreeView x:Name="TreeView" Width="400" Height="800" Focusable="True" VerticalAlignment="Top">
</TreeView>
</Border>
</StackPanel>
Instead of Tree View you can use Expander. Which can scoll With Scroll view properly this work same as Treeview.
How about just setting the height and width to a fixed amount?
I know this might not be the answer for everyone.

Resources