Developing checkboxes in databound WPF treeview leafs - wpf

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.

Related

Showing a different view for treeview item selected

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

WPF TreeViewItem default icon for each parent node

How would I add an icon to each of these parent nodes
I tried adding under each TreeViewItem but the icon doesn't show and when I bind my collection to the ItemSource, it says it must be empty fist.
<TreeView x:Name="tvMessages" HorizontalAlignment="Left" Height="262" Margin="10,37,0,0" VerticalAlignment="Top" Width="248">
<TreeViewItem x:Name="itemsCritical" Header="Critical">
<TreeViewItem.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Description}"/>
<TextBlock Text="{Binding ID}" Visibility="Hidden"/>
</StackPanel>
</DataTemplate>
</TreeViewItem.ItemTemplate>
</TreeViewItem>
<TreeViewItem x:Name="itemsAlert" Header="Alert">
<TreeViewItem.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Description}"/>
<TextBlock Text="{Binding ID}" Visibility="Hidden"/>
</StackPanel>
</DataTemplate>
</TreeViewItem.ItemTemplate>
</TreeViewItem>
<TreeViewItem x:Name="itemsInformational" Header="Informational">
<TreeViewItem.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Description}"/>
<TextBlock Text="{Binding ID}" Visibility="Hidden"/>
</StackPanel>
</DataTemplate>
</TreeViewItem.ItemTemplate>
</TreeViewItem>
</TreeView>
Take a look at this example:
<TreeViewItem Name="treeViewItem1" IsEnabled="True">
<TreeViewItem.Header>
<StackPanel Orientation="Horizontal">
<Image Height="16" Source="Images/16x16_red_lamp.png" Width="16" />
<TextBlock Margin="5,0" Text="HostA: Disconnected" />
</StackPanel>
</TreeViewItem.Header>
</TreeViewItem>
Just place the Image inside and tell the Source where is your Icon located.
You can also use HeaderTemplate in case you have Bindings against associated item.

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

WPF/XAML TreeView doesn't Hightlight Nodes after Binding

So I am having an issue with the TreeView. If I build a tree view statically, every node in the tree is selectable in that when I click on it, it highlights itself blue, indicating that node is selected.
<TreeView
Grid.Column="0"
Grid.Row="2"
MinHeight="100"
MinWidth="100"
BorderBrush="White"
DataContext="{Binding Projects, Source={x:Static SizingApp:Manager.Instance}}">
<TreeViewItem Header="Project 1" IsExpanded="True">
<TreeViewItem Header="Step 1" IsExpanded="True">
<TreeViewItem Header="Load 1" IsExpanded="True"></TreeViewItem>
<TreeViewItem Header="Load 2" IsExpanded="True"></TreeViewItem>
</TreeViewItem>
<TreeViewItem Header="Step 2" IsExpanded="True">
<TreeViewItem Header="Load 1" IsExpanded="True"></TreeViewItem>
<TreeViewItem Header="Load 2" IsExpanded="True"></TreeViewItem>
</TreeViewItem>
</TreeViewItem>
However, I am Binding to the TreeView to populate it. Furthermore, I am binding to objects that implement Emiel Jongerius's BindableObjectBase3 class. This is a wonderful base class implementation that allows my objects to be Bindable and implement the INotifyPropertyChanged interface with the concern for manual DependencyProperty management.
So this is the basic class structure (simplified from my actual objects) that I am trying to implement in a TreeView.
public abstract class MyCustomClass : BindableObjectBase3
{
private string m_strName;
public virtual string Name
{
get
{
using (this.GetPropertyTracker(() => this.Name))
{
return m_strName;
}
}
set
{
this.SetValue(ref this.m_strName, value, () => this.Name);
}
}
}
public class Project : MyCustomClass
{
private List<Step> m_steps;
public List<Step> Steps
{
get
{
using (this.GetPropertyTracker(() => this.Steps))
{
return m_steps;
}
}
set
{
this.SetValue(ref this.m_steps, value, () => this.Steps);
}
}
}
public class Step : MyCustomClass
{
private List<Load> m_loads;
public List<Load> Loads
{
get
{
using (this.GetPropertyTracker(() => this.Loads))
{
return m_loads;
}
}
set
{
this.SetValue(ref this.m_loads, value, () => this.Steps);
}
}
}
public class Load : MyCustomClass
{
}
And this is the basic XAML I use to implement the TreeView:
<TreeView
Grid.Column="0"
Grid.Row="2"
MinHeight="100"
MinWidth="100"
BorderBrush="White"
DataContext="{Binding Projects, Source={x:Static SizingApp:Manager.Instance}}">
<TreeView.Resources>
<HierarchicalDataTemplate x:Key="LoadTemplate">
<TreeViewItem Header="{Binding Path=Name}">
</TreeViewItem>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate x:Key="StepTemplate">
<TreeViewItem Header="{Binding Path=Name}" IsExpanded="True"
ItemsSource="{Binding Path=Loads}"
ItemTemplate="{StaticResource LoadTemplate}">
</TreeViewItem>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate x:Key="ProjectTemplate">
<TreeViewItem Header="{Binding Path=Name}" IsExpanded="True"
ItemsSource="{Binding Path=Steps}"
ItemTemplate="{StaticResource StepTemplate}">
</TreeViewItem>
</HierarchicalDataTemplate>
</TreeView.Resources>
<TreeViewItem
Header="{Resx ResxName=PSSPECApplication.Controls.ProjectControlResources, Key=projectTree_Header}"
ItemsSource="{Binding}"
IsExpanded="True"
Focusable="True"
ItemTemplate="{StaticResource ProjectTemplate}">
</TreeViewItem>
</TreeView>
Now all of this works fine as far as binding goes. I can bind to an ObservableCollection<Project> and as I add/remove/manipulate projects, the TreeView updates accordingly.
However, the only node in the TreeView that seems selectable is the first node (the one that is static). All of the other nodes create through dynamic Binding do not indicate that they are selected on the GUI. I would expect that they would also highlight blue when clicked on. But instead they do nothing. Does anyone have an idea of why?
You shouldn't be defining TreeViewItems explicitly in your ItemTemplates. The reason you can't select any of the items is that they have no parent TreeView to control selection behavior. You need to let the TreeView generate the TreeViewItem controls for you and only use the item templates to define the UI for the Headers and the bindings for their items. Use something like this instead:
<Window.Resources>
<HierarchicalDataTemplate x:Key="LoadTemplate">
<TextBlock Text="{Binding Path=Name}"/>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate x:Key="StepTemplate" ItemsSource="{Binding Loads}" ItemTemplate="{StaticResource LoadTemplate}">
<TextBlock Text="{Binding Path=Name}"/>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate x:Key="ProjectTemplate" ItemsSource="{Binding Steps}" ItemTemplate="{StaticResource StepTemplate}">
<TextBlock Text="{Binding Path=Name}"/>
</HierarchicalDataTemplate>
</Window.Resources>
<TreeView MinHeight="100" MinWidth="100" BorderBrush="White"
ItemsSource="{Binding Path=Projects}"
ItemTemplate="{StaticResource ProjectTemplate}">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="True" />
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
My TreeView is acting just as the original poster has described. I'm able to select everything in my TreeView Control but If I select a childnode the Parent Node is what Highlights even though It binds and clicks the child. I tried structuring my code to resemble John Bowen's suggestion and still get the same results. Here is my XAML Code:
<Fluent:RibbonWindow.Resources>
<HierarchicalDataTemplate x:Key="MyTreeViewStyle" ItemsSource="{Binding Contacts}">
<!-- Display the Index by showing it's Index string -->
<StackPanel Orientation="Horizontal">
<Image x:Name="img" Width="16" Height="16" Stretch="Fill" Source="Images\closedfolder16.png" />
<TextBlock Text="{Binding Index}" Margin="5,0" ToolTip="{Binding Index}"/>
</StackPanel>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image x:Name="img2" Width="16" Height="16" Stretch="Fill" Source="Images\closedfolder16.png" />
<TextBlock Text="{Binding Name}" Margin="5,0" ToolTip="{Binding Name}"/>
</StackPanel>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</Fluent:RibbonWindow.Resources>
Then I use it here in my TreeView Control:
<Grid>
<TreeView Margin="2,2,2,2" x:Name="MyTreeView" ItemTemplate="{StaticResource MyTreeViewStyle}" ItemContainerStyle="{StaticResource AlwaysExpand}" ScrollViewer.CanContentScroll="True" BorderThickness="0" TreeViewItem.Selected="btnDisplayContact_Click" />
</Grid>
The result is this screenshot, notice how the parent node D is highlighted after clicking the child node, instead of the child node being highlighted:
http://home.swbell.net/davis32/Snapshot.png
Can't post images so just cut and paste the URL link.

WPF: Combobox in TreeviewItem

I'm newbie in WPF, so sorry about stupid question.
It is possible to show combobox side by side with selected TreeViewItem?
I need something like shown in the left picture at the following link: http://www.mypicx.com/03242009/Combobox_in_TreeviewItem/
I tried to do thus:
<TreeView Name="treeView1">
<TreeViewItem Header="aaa">
<ComboBox Height="19">
<ComboBoxItem Content="111" IsSelected="True"></ComboBoxItem>
<ComboBoxItem>222</ComboBoxItem>
<ComboBoxItem Content="333"></ComboBoxItem>
</ComboBox>
<TreeViewItem Header="aaa1">
</TreeViewItem>
<TreeViewItem Header="aaa2">
</TreeViewItem>
</TreeViewItem>
<TreeViewItem Header="bbb">
<TreeViewItem Header="bbb1" />
<TreeViewItem Header="bbb2" />
</TreeViewItem>
<TreeViewItem Header="ccc" />
</TreeView>
and the result you can see in the right picture.
Meantime I need to know, how to do this visually. Later I need to do something with SelectedItemChanged event.
Thanks in advance!
P.S. sorry about my english
What you need to do is put your combo box inside your Header like such
<TreeView Name="treeView1">
<TreeViewItem>
<TreViewItem.Header>
<StackPanel Orientation="Horizontal">
<ComboBox Height="19">
<ComboBoxItem Content="111" IsSelected="True"></ComboBoxItem>
<ComboBoxItem>222</ComboBoxItem>
<ComboBoxItem Content="333"></ComboBoxItem>
</ComboBox>
</StackPanel>
</TreViewItem.Header>
<TreeViewItem Header="aaa1">
</TreeViewItem>
<TreeViewItem Header="aaa2">
</TreeViewItem>
</TreeViewItem>
<TreeViewItem Header="bbb">
<TreeViewItem Header="bbb1" />
<TreeViewItem Header="bbb2" />
</TreeViewItem>
<TreeViewItem Header="ccc" />
</TreeView>
Use an ItemTemplate. http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/ec6781bb-a81d-4204-bc13-937683110b0d/

Resources