Showing a different view for treeview item selected - wpf

I am trying to build a help module with a treeview and the goal is to have a different view show up in the redbox based on selected treeview item. how would I go about to do that?
This is all the code I have:
<Grid ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TreeView Margin="2" Width="250" HorizontalAlignment="Left" Height="auto" IsEnabled="True" FontSize="20">
<TreeViewItem Header="Introduction">
</TreeViewItem>
<TreeViewItem Header="Logging in" Margin="0,10,0,0">
<TreeViewItem Header="Changing Password" Margin="0,10,0,0"/>
</TreeViewItem>
<TreeViewItem Header="Home" Margin="0,10,0,0">
<TreeViewItem Header="Dashboard Elements" Margin="0,10,0,0"/>
<TreeViewItem Header="Parking Spots" Margin="0,10,0,0" />
<TreeViewItem Header="Docking Spots" Margin="0,10,0,0"/>
</TreeViewItem>
<TreeViewItem Header="Log Table" Margin="0,10,0,0"/>
<TreeViewItem Header="Security" Margin="0,10,0,0">
<TreeViewItem Header="Domestic Trucks" Margin="0,10,0,0"/>
<TreeViewItem Header="International Trucks" Margin="0,10,0,0"/>
</TreeViewItem>
<TreeViewItem Header="Administration" Margin="0,10,0,0" Visibility="{Binding Source={x:Static model:ViewModel.CurrentUser}, Path=IsAdmin, Converter={StaticResource My.Converter.BoolToHidden}}">
<TreeViewItem Header="Permissions" Margin="0,10,0,0"/>
<TreeViewItem Header="Editing a User" Margin="0,10,0,0"/>
<TreeViewItem Header="Adding a new company" Margin="0,10,0,0"/>
</TreeViewItem>
</TreeView>
</Grid>

I really think that this Control is not doing what you expect. I would rather use Markdown to create a help file and save it to html, pdf or xps. You can open this document when the user hits the help button. IMO it is not a good idea to "hard-code" a Help module.
But to answer your question any way, you can do it this way:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TreeView x:Name="TreeView_TOC">
<TreeViewItem Header="Chapeter 1">
<TreeViewItem.Tag>
<TextBlock Text="Your Content goes here" />
</TreeViewItem.Tag>
</TreeViewItem>
</TreeView>
<ContentControl Grid.Column="1"
Content="{Binding ElementName=TreeView_TOC, Path=SelectedItem.Tag, Mode=OneWay}"/>
</Grid>
Happy documenting
Tim

Related

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" />

Developing checkboxes in databound WPF treeview leafs

I have the next WPF treeview:
<TreeView HorizontalAlignment="Left" Margin="6,0,0,32" Name="tvProductos" Width="158">
<TreeViewItem Header="Securities" IsExpanded="True" FontWeight="Bold">
<TreeViewItem Header="Country" Name="Country" FontWeight="Normal" />
<TreeViewItem Header="Currency" Name="Currency" FontWeight="Normal" />
<TreeViewItem Header="Type" Name="Type" FontWeight="Normal" />
<TreeViewItem Header="ISIN" Name="ISIN" FontWeight="Normal" />
<TreeViewItem Header="Description" Name="Description" FontWeight="Normal" />
</TreeViewItem>
<TreeViewItem Header="Issuer" IsExpanded="True" FontWeight="Bold">
<TreeViewItem Header="Name" Name="IssuerName" FontWeight="Normal" />
<TreeViewItem Header="Type" Name="IssuerType" FontWeight="Normal" />
<TreeViewItem Header="Market" Name="IssuerMarket" FontWeight="Normal" />
</TreeViewItem>
</TreeView>
This structure is fixed. Then I bind low level TreeViewItems using code like this:
Country.ItemsSource = (from d in db.PAISES
join p in db.PRODUCTOS on d.IDPAIS equals p.IDPAIS
select d.NOMBREPAIS).Distinct();
Currency.ItemsSource = (from d in db.DIVISAS
join p in db.PRODUCTOS on d.IDDIVISA equals p.IDDIVISA
select d.NOMBREDIVISA).Distinct();
Type.ItemsSource = (from d in db.TIPOSPRODUCTO
join p in db.PRODUCTOS on d.IDTIPOPRODUCTO equals p.IDTIPOPRODUCTO
select d.NOMBRETIPOPRODUCTO).Distinct();
...
The problem is that I need to add one checkbox on each node (low and high level). I have been looking for a solution and the best one is using HierarchicalDataTemplate. But I never found a example with fixed and dynamic nodes at same time. I tried with several examples but I couldn't solve it.
Can you help me on this?
Thank you in advance.
Kind Regards.
The way I'd do it is using a helper class that represents the items that can be checked (some would call it a "view model"):
public class SelectableItem
{
public bool IsSelected { get; set; }
public string Label { get; set; }
}
This allows you to specify a DataTemplate for this specific type:
<TreeView HorizontalAlignment="Left" Margin="6,0,0,32" Name="tvProductos" Width="158">
<TreeView.Resources>
<DataTemplate DataType="{x:Type local:SelectableItem}" xmlns:local="clr-namespace:WpfApplication1">
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsSelected}" />
<TextBlock Text="{Binding Label}" />
</StackPanel>
</DataTemplate>
</TreeView.Resources>
<TreeViewItem Header="Securities" IsExpanded="True" FontWeight="Bold">
<TreeViewItem Header="Country" Name="Country" FontWeight="Normal" />
<TreeViewItem Header="Currency" Name="Currency" FontWeight="Normal" />
<TreeViewItem Header="Type" Name="Type" FontWeight="Normal" />
<TreeViewItem Header="ISIN" Name="ISIN" FontWeight="Normal" />
<TreeViewItem Header="Description" Name="Description" FontWeight="Normal" />
</TreeViewItem>
<TreeViewItem Header="Issuer" IsExpanded="True" FontWeight="Bold">
<TreeViewItem Header="Name" Name="IssuerName" FontWeight="Normal" />
<TreeViewItem Header="Type" Name="IssuerType" FontWeight="Normal" />
<TreeViewItem Header="Market" Name="IssuerMarket" FontWeight="Normal" />
</TreeViewItem>
</TreeView>
All you need to do is modify slightly your data sources:
Country.ItemsSource = (from d in db.PAISES
join p in db.PRODUCTOS on d.IDPAIS equals p.IDPAIS
select new SelectableItem { Label = d.NOMBREPAIS }).Distinct();
And that should do the trick.

Adding an image to tree view in wpf

I have a treeview control in wpf..i need to add an image at evry node.how is it possible?
If you want to have unique images for each node, you can do something like:
<TreeView>
<TreeViewItem>
<TreeViewItem.Header>
<Image Source="/WpfApplication2;component/folder.png" Height="25" Width="25"/>
</TreeViewItem.Header>
</TreeViewItem>
<TreeViewItem>
<TreeViewItem.Header>
<Image Source="/WpfApplication2;component/folder1.png" Height="25" Width="25"/>
</TreeViewItem.Header>
</TreeViewItem>
<TreeViewItem>
<TreeViewItem.Header>
<Image Source="/WpfApplication2;component/folder2.png" Height="25" Width="25"/>
</TreeViewItem.Header>
</TreeViewItem>
<TreeViewItem>
<TreeViewItem.Header>
<Image Source="/WpfApplication2;component/folder3.png" Height="25" Width="25"/>
</TreeViewItem.Header>
</TreeViewItem>
</TreeView>
or, if you want to have the same image for each node, you can do something like this:
<Window.Resources>
<Image Source="/WpfApplication2;component/folder.png" Height="25" Width="25" x:Key="FolderIcon" x:Shared="false"/>
</Window.Resources>
<Grid>
<TreeView>
<TreeViewItem>
<TreeViewItem.Header>
<StaticResourceExtension ResourceKey="FolderIcon"/>
</TreeViewItem.Header>
</TreeViewItem>
<TreeViewItem>
<TreeViewItem.Header>
<StaticResourceExtension ResourceKey="FolderIcon"/>
</TreeViewItem.Header>
</TreeViewItem>
<TreeViewItem>
<TreeViewItem.Header>
<StaticResourceExtension ResourceKey="FolderIcon"/>
</TreeViewItem.Header>
</TreeViewItem>
<TreeViewItem>
<TreeViewItem.Header>
<StaticResourceExtension ResourceKey="FolderIcon"/>
</TreeViewItem.Header>
</TreeViewItem>
</TreeView>
</Grid>
Hope this helps.
UPDATE to answer the following question: "how can i change the image/icon on clicking/expanding the node"
Here is a quick and dirty solution.
Xaml:
<Window.Resources>
<Image Source="/WpfApplication2;component/folder.png" Height="25" Width="25" x:Key="FolderIcon" x:Shared="false"/>
<Image Source="/WpfApplication2;component/folderOpened.jpg" Height="25" Width="25" x:Key="FolderOpenIcon" x:Shared="false"/>
</Window.Resources>
<Grid>
<TreeView>
<TreeViewItem PreviewMouseLeftButtonDown="itemExpanded" Name="treeViewItem">
<TreeViewItem.Header>
<StaticResourceExtension ResourceKey="FolderIcon"/>
</TreeViewItem.Header>
<TreeViewItem>
<TreeViewItem/>
</TreeViewItem>
</TreeViewItem>
</TreeView>
</Grid>
C# / Code-behind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void itemExpanded(object sender, RoutedEventArgs e)
{
if (treeViewItem.IsExpanded)
{
treeViewItem.Header = FindResource("FolderIcon");
}
else
{
treeViewItem.Header = FindResource("FolderOpenIcon");
}
}
}
You can also accomplish this using the "Expanded" event as well. If you want eliminate "code-behind" you can also do this using a Command or Converter.
Move image to resource section and set x:Shared="False":
<Window.Resources>
<Image Source="links.png" x:Key="imgLinks" x:Shared="False"/>
Use it in template:<StaticResource ResourceKey="imgLinks"/>

How to keep an area a constant/relative size while user expands/collapses treeview?

I have a window that will be a variable size, currently it is 300 x 400 as shown below.
In the top part I have an expandable tree view
In the bottom part I have a long horizontal panel with a button in it.
I want the top area (treeview) to be about 95% of the height, with the button tool area a constant 50 high.
I want these proportions to stay constant as the user expands and collapses the tree view (and as it expands below the button toolbar, I want the viewscroller to pop in with a scrollbar.
How can I do this? Here's the best I could do so far, but the button area moves up as the user collapses the tree view. :
<Window x:Class="TestSize8383.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="400">
<Window.Resources>
<Style TargetType="TreeViewItem">
<Setter Property="IsExpanded" Value="True" />
</Style>
</Window.Resources>
<DockPanel Background="Beige" Margin="3" LastChildFill="False">
<ScrollViewer DockPanel.Dock="Top" Background="White" Margin="3">
<TreeViewItem DockPanel.Dock="Top" Background="White" Header="Page 1" IsExpanded="True">
<TreeViewItem Header="Part 1">
<TreeViewItem Header="Paragraph 1">
<TreeViewItem Header="Word 1"/>
<TreeViewItem Header="Word 2"/>
</TreeViewItem>
<TreeViewItem Header="Paragraph 2">
<TreeViewItem Header="Word 1"/>
<TreeViewItem Header="Word 2"/>
</TreeViewItem>
<TreeViewItem Header="Paragraph 3">
<TreeViewItem Header="Word 1"/>
<TreeViewItem Header="Word 2"/>
</TreeViewItem>
<TreeViewItem Header="Part 2">
<TreeViewItem Header="Paragraph 1">
<TreeViewItem Header="Word 1"/>
<TreeViewItem Header="Word 2"/>
</TreeViewItem>
<TreeViewItem Header="Paragraph 2">
<TreeViewItem Header="Word 1"/>
<TreeViewItem Header="Word 2"/>
</TreeViewItem>
<TreeViewItem Header="Paragraph 3">
<TreeViewItem Header="Word 1"/>
<TreeViewItem Header="Word 2"/>
</TreeViewItem>
</TreeViewItem>
</TreeViewItem>
</TreeViewItem>
</ScrollViewer>
<StackPanel DockPanel.Dock="Bottom" Background="Tan" Margin="3" Height="50">
<Button Content="Previous" Margin="5"/>
</StackPanel>
</DockPanel>
</Window>
How about using a Grid instead of using a DockPanel?
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<ScrollViewer Grid.Row="0">
...
</ScrollViewer>
<StackPanel Grid.Row="1">
...
</StackPanel>
</Grid>
Based on the fixed layout you describe, I would use a Grid instead of DockPanel like so:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<ScrollViewer Grid.Row="0">
<TreeView>
<!-- items excluded for brevity -->
</TreeView>
</ScrollViewer>
<StackPanel Grid.Row="1" Background="Tan" Margin="3">
<Button Content="Previous" Margin="5" />
</StackPanel>
</Grid>
You said the button must be a constant height of about 50 then immediately after that you talk about proportions? I'm not certain I understood you, but here is what I have for you in the meantime.
Make the DockPanel to have LastChildFill = True
Put the StackPanel above the ScrollViewer (first in the XAML code)
Make the ScrollViewer have VerticalScrollBarVisibility="Auto"
This will have these effects:
The button bar will always be visible
The scrollbar will pop into view when it is needed only

Strange WPF errors in Visual Studio

Does anybody know of the reason why ""could not create instance of UserControl"" error can occur. It seems to me that it occurs completely spontanous, for example after I add space after node or change tabulation. Maybe it's some kind of VS bug?
Here are controls. This configuration actually raises an error
<UserControl x:Class="ShortcutsPrototype.KeyboardShortcutsTreePanel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ShortcutsPrototype="clr-namespace:ShortcutsPrototype">
<Grid Margin="3,3,3,3">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="80" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="30" />
</Grid.RowDefinitions>
<ShortcutsPrototype:KeyboardShortcutsTreeView />
<Button Grid.Row="1" Margin="3,3,3,3" Grid.Column="1" HorizontalAlignment="Stretch">Reset</Button>
</Grid>
</UserControl>
<UserControl x:Class="ShortcutsPrototype.KeyboardShortcutsTreeView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ShortcutsPrototype="clr-namespace:ShortcutsPrototype"
Height="300" Width="300">
<Grid>
<TreeView>
<TreeViewItem HorizontalContentAlignment="Stretch">
<TreeViewItem.Header>
<ShortcutsPrototype:KeyboardShortcutsTreeViewEntry x:Name="generalTreeViewEntry" Title="General" />
</TreeViewItem.Header>
<TreeViewItem HorizontalContentAlignment="Stretch">
<TreeViewItem.Header>
<ShortcutsPrototype:KeyboardShortcutsTreeViewEntry x:Name="generalNewFileTreeViewEntry" Title="New File" ShortcutKey="Ctrl+N" />
</TreeViewItem.Header>
</TreeViewItem>
<TreeViewItem HorizontalContentAlignment="Stretch">
<TreeViewItem.Header>
<ShortcutsPrototype:KeyboardShortcutsTreeViewEntry x:Name="generalOpenFileTreeViewEntry" Title="Open File" ShortcutKey="Ctrl+O" />
</TreeViewItem.Header>
</TreeViewItem>
<TreeViewItem HorizontalContentAlignment="Stretch">
<TreeViewItem.Header>
<ShortcutsPrototype:KeyboardShortcutsTreeViewEntry x:Name="generalSaveFileTreeViewEntry" Title="Save File" ShortcutKey="Ctrl+S" />
</TreeViewItem.Header>
</TreeViewItem>
<TreeViewItem HorizontalContentAlignment="Stretch">
<TreeViewItem.Header>
<ShortcutsPrototype:KeyboardShortcutsTreeViewEntry x:Name="generalSaveAsFileTreeViewEntry" Title="Save File As.." ShortcutKey="Ctrl+Shift+S" />
</TreeViewItem.Header>
</TreeViewItem>
</TreeViewItem>
<TreeViewItem HorizontalContentAlignment="Stretch">
<TreeViewItem.Header>
<ShortcutsPrototype:KeyboardShortcutsTreeViewEntry x:Name="debugerTreeViewEntry" Title="Debuger" />
</TreeViewItem.Header>
</TreeViewItem>
<TreeViewItem HorizontalContentAlignment="Stretch">
<TreeViewItem.Header>
<ShortcutsPrototype:KeyboardShortcutsTreeViewEntry x:Name="refactoringTreeViewEntry" Title="Refactoring" />
</TreeViewItem.Header>
</TreeViewItem>
</TreeView>
</Grid>
</UserControl>
<UserControl x:Class="ShortcutsPrototype.KeyboardShortcutsTreeViewEntry"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="25">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<Label x:Name="titleLabel" Grid.Column="0"></Label>
<Label x:Name="shortcutLabel" Grid.Column="1"></Label>
</Grid>
</UserControl>
Perhaps something in your CodeBehind file is throwing an exception. Have you checked that?
I have found that visual studio has quite the difficult time with WPF user controls.
The only thing that I can see is that it seems to use the latest compiled version of a control. Usually, building the solution will fix the errors I have. Sometimes, if I have multiple projects I have to build them manually one by one.

Resources