WPF Treeview Icon Plus Minus - wpf

I'm trying to add icons in my treeview but it's not showing up. The HierarchicalDataTemplate is in the windows resources and treeview is in the Grid.
Can any body tell me what is the mistake i'm making?
Here is the XML:
<Window x:Class="Treeview.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Support" Height="700" Width="1024" SizeToContent="WidthAndHeight"
mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="229" Icon="/Test;component/Images/Treeview.jpg">
<Window.Resources>
<XmlDataProvider x:Key="questions" XPath="Questions/Question" />
<HierarchicalDataTemplate x:Key="rootTemplate">
<HierarchicalDataTemplate.ItemsSource>
<Binding XPath="child::*" />
</HierarchicalDataTemplate.ItemsSource>
<StackPanel Orientation="Horizontal">
<CheckBox Name="checkBoxTree" Checked="TreeView_Checked" Unchecked="checkBoxTree_Unchecked" />
<Image Style="{StaticResource ExpandingImageStyle}">
<Image.Resources>
<BitmapImage x:Key="Icon_Closed" UriSource="Images/Plus.ico"/>
<BitmapImage x:Key="Icon_Open" UriSource="Images/Minus.ico"/>
</Image.Resources>
</Image>
<TextBlock Text="{Binding XPath=#Name, Mode=TwoWay}" />
<TextBlock>
<Hyperlink NavigateUri="{Binding XPath=#WebSite}" RequestNavigate="Hyperlink_RequestNavigate">
<TextBlock Text="{Binding XPath=#WebSite}" />
</Hyperlink>
</TextBlock>
</StackPanel>
</HierarchicalDataTemplate>
</Window.Resources>
<Grid>
<TreeView Name="TreeViewer" HorizontalAlignment="Left" Height="220" Margin="10,116,0,0" Grid.Row="1"
VerticalAlignment="Top" Width="700" Visibility="Collapsed" FontSize="15"
ItemsSource="{Binding Source={StaticResource questions}}" ItemTemplate="{StaticResource rootTemplate}" >
<TreeView.Resources>
<Style x:Key="ExpandingImageStyle" TargetType="{x:Type Image}">
<Setter Property="Source" Value="{DynamicResource Icon_Closed}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=TreeViewItem}, Path=IsExpanded}" Value="True">
<Setter Property="Source" Value="{DynamicResource Icon_Open}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TreeView.Resources>
</TreeView>
</Grid>
</Window>

Surely with that XAML you have a Warning shown in the Visual Studio Error List like the following?:
The resource "ExpandingImageStyle" could not be resolved.
This is telling you that your HierarchicalDataTemplate can't find the Resource. If you move that Style to the top of your Window.Resources, the first problem should disappear. However, when you do that, you'll then get a warning that the Style can't find the two BitmapImage Resources. So you'd better move those two Resources to the top of your Window.Resources:
<BitmapImage x:Key="Icon_Closed" UriSource="Images/Plus.ico"/>
<BitmapImage x:Key="Icon_Open" UriSource="Images/minus.ico"/>
<Style x:Key="ExpandingImageStyle" TargetType="{x:Type Image}">
...
</Style>
<XmlDataProvider x:Key="questions" XPath="Questions/Question" />
<HierarchicalDataTemplate x:Key="rootTemplate">
...
<Image Style="{StaticResource ExpandingImageStyle}" />
...
</HierarchicalDataTemplate>
If you find that that still doesn't work, please take a look at any errors or warnings that you may get in either the Error List or Output Window in Visual Studio and let us know.

Related

Using the Treeview HierarchicalDataTemplate.Triggers to change folder icon

I'm pretty fresh to WPF and this is the closest I have come to achieving what I set out to do after reviewing many of the previously asked questions posted here.
The XAML code:
<TreeView x:Name="folderView" Grid.Column="0" Grid.Row="1" BorderThickness="0">
<TreeViewItem Header="Folders" ItemsSource="{Binding SubFolders, Source={StaticResource RootFolderDataProvider}}" Margin="5"/>
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type my:FolderView}" ItemsSource="{Binding SubFolders}">
<StackPanel Orientation="Horizontal" Name="myPanel">
<Image x:Name="img" Width="16" Height="16" Source="Images/FolderClosed.png" />
<TextBlock Text="{Binding Name}" />
</StackPanel>
<HierarchicalDataTemplate.Triggers>
<DataTrigger Binding="{Binding IsExpanded}" Value="True">
<Setter TargetName="img" Property="Source" Value="Images/FolderOpen.png"/>
</DataTrigger>
</HierarchicalDataTemplate.Triggers>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
This displays the FolderClosed image on all my subfolders except the very top root folder.
The HierachicalDataTemplate trigger also fails to fire when expanded.
Any help would be appreciated.
If you are binding to the TreeViewItem IsExpanded property, then you will have to update your binding like:
<DataTrigger Binding="{Binding IsExpanded, RelativeSource={RelativeSource AncestorType={x:Type TreeViewItem}}}" Value="True">
<Setter TargetName="img" Property="Source" Value="Images/FolderOpen.png"/>
</DataTrigger>
I cannot pin point the issues. But as a first step you should check if the binding is working or not.
you can add debugging for binding as mentioned in here
eg :
<Window
xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
xmlns:local="clr-namespace:DebugDataBindings"
x:Class="DebugDataBindings.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">
<Grid x:Name="layoutRoot">
<Grid.Resources>
<local:DebugConverter x:Key="debugConverter" />
</Grid.Resources>
<TextBox
Text="{Binding Path=Customer.FirstName, diag:PresentationTraceSources.TraceLevel=High}"
Height="23" HorizontalAlignment="Left" Margin="90,18,0,0" VerticalAlignment="Top" Width="120"/>
</Grid>
</Window>

Change listbox template on lost focus event in WPF

I want to present a listbox with TextBlocks as items. When the user clicks/selects an item it changes into a TextBox for editing. As soon as the controls loses focus the item would turn back to a TextBlock.
The following XAML is almost working in that the TextBlock does turn into a TextBox when it's selected. It also turns back to a TextBlock if I select another item on the list. The problem is that if I move out of the listbox (in this case to the Add New text box) the list item stays as a TextBox.
The question ( WPF ListViewItem lost focus event - How to get at the event? ) looked promising but I can't make it work. I tried using the IsFocused property but then I wasn't able to edit the textbox because when I got into the textbox the listboxitem would go out of focus and thus turning back to a TextBlock before I had a chance to edit the text.
How can I make the TextBox turn back to TextBlock if the listbox/item loses the focus?
(Any other implementation that accomplishes the goal are also welcomed)
<Window x:Class="MyView.MainWindow1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
Title="MainWindow1" Height="300" Width="200">
<Window.Resources>
<DataTemplate x:Key="ItemTemplate">
<TextBlock Text="{Binding Name}" />
</DataTemplate>
<DataTemplate x:Key="SelectedTemplate">
<TextBox Text="{Binding Name, Mode=TwoWay}" />
</DataTemplate>
<Style TargetType="{x:Type ListBoxItem}" x:Key="ContainerStyle">
<Setter Property="ContentTemplate" Value="{StaticResource ItemTemplate}" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="ContentTemplate" Value="{StaticResource SelectedTemplate}" />
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel >
<ListBox ItemsSource="{Binding Departments}" HorizontalContentAlignment="Stretch"
ItemContainerStyle="{StaticResource ContainerStyle}" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox Text="{Binding NewDepartmentName, Mode=TwoWay}" />
<Button Grid.Column="1" Width="50" Content="Add" Command="{Binding Path=AddNewDepartmentCommand}" />
</Grid>
</StackPanel>
</Window>
This doesn't answer your question, but gives an alternative solution by making a textbox look like a textblock when the listboxitem isn't selected:
<Page.Resources>
<ResourceDictionary>
<Style x:Key="ListBoxSelectableTextBox" TargetType="{x:Type TextBox}">
<Setter Property="IsHitTestVisible" Value="False" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}, AncestorLevel=1}}" Value="True">
<Setter Property="IsHitTestVisible" Value="True" />
</DataTrigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
</Page.Resources>
<Grid>
<ListBox ItemsSource="{Binding Departments}" HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Margin="5" Style="{StaticResource ListBoxSelectableTextBox}" Text="{Binding Name}" BorderBrush="{x:Null}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
There are many ways you can do this:
Above answer
Create a TextBox style based on TextBoxBase such that when disabled, it makes the TextBox look like a TextBlock by setting the BorderThickness="0", Background="transparent"
Have both TextBlock and TextBox on each ListViewItem and using the above answer technique hide and show the TextBlock/TextBox accrodingly

Clicking TreeView item to select not working

I have a tree with a hierarchical data template
<HierarchicalDataTemplate DataType="{x:Type local:TreeItem}" ItemsSource="{Binding Path=Children}" >
<TreeViewItem Focusable="True" ToolTip="{Binding ToolTipText}" >
<TreeViewItem.Header>
<StackPanel Orientation="Horizontal" Focusable="True" >
<Image Width="16" Height="16" Margin="3,0">
<Image.Source>
<Binding
Path="IsLeaf" Converter="{StaticResource cnvIsBooleanToStringArrayItemConverter}">
<Binding.ConverterParameter>
<x:Array Type="sys:String">
<sys:String>..\Images\document_plain.png</sys:String>
<sys:String>..\Images\folder.png</sys:String>
</x:Array>
</Binding.ConverterParameter>
</Binding>
</Image.Source>
</Image>
<TextBlock MaxWidth="300" Text="{Binding Desc}" Focusable="True" />
</StackPanel>
</TreeViewItem.Header>
</TreeViewItem>
</HierarchicalDataTemplate>
I want to select an item by clicking at the TextBlock containing "Desc", but the only way to select an item is by clicking in the space left of the text (the image area)
Any clues what is missing?
Regards
Klaus
Your data template specifies a TreeViewItem at its root, but the TreeView will automatically create a TreeViewItem around your template, having a TreeViewItem in a TreeViewItem confuses the selection mechanism.
Do something like this:
<HierarchicalDataTemplate DataType="{x:Type local:TreeItem}" ItemsSource="{Binding Path=Children}">
<HierarchicalDataTemplate.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="ToolTip" Value="{Binding ToolTipText}"/>
<Setter Property="Focusable" Value="True"/>
<Setter Property="Header">
<Setter.Value>
...
</Setter.Value>
</Setter>
</Style>
</HierarchicalDataTemplate.ItemContainerStyle>
</HierarchicalDataTemplate>
Edit:
After some testing it turns out that messing with the container is quite troublesome, i did not get it display the tooltip that way, unless you found a way to do it i recommend you stick to only setting HierarchicalDataTemplate.VisualTree (the default content of HierarchicalDataTemplate) which will be placed in the header of the auto-generated TreeViewItem.
As H.B. says, you should not put a TreeViewItem inside your hierarchical data template, since WPF will automatically create one to wrap your content.
If you want to bind to the ToolTip, you can do it inside the ItemContainerStyle, which will apply to all your treeview items within the TreeView.
<TreeView .... your parameters >
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="ToolTip" Value="{Binding ToolTipText}"/>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
I hope this helps.
Although I haven't tested it, I think your hierarchical data template should look like this:
<HierarchicalDataTemplate DataType="{x:Type local:TreeItem}" ItemsSource="{Binding Path=Children}" >
<StackPanel Orientation="Horizontal">
<Image Width="16" Height="16" Margin="3,0">
<Image.Source>
<Binding Path="IsLeaf" Converter="{StaticResource cnvIsBooleanToStringArrayItemConverter}">
<Binding.ConverterParameter>
<x:Array Type="sys:String">
<sys:String>..\Images\document_plain.png</sys:String>
<sys:String>..\Images\folder.png</sys:String>
</x:Array>
</Binding.ConverterParameter>
</Binding>
</Image.Source>
</Image>
<TextBlock MaxWidth="300" Text="{Binding Desc}"/>
</StackPanel>
</HierarchicalDataTemplate>
You may need to set the Background="Transparent" on the StackPanel and/or remove the Focusable setting on the TextBlock.

WPF Tooltip Binding

I am only two weeks into WPF so this is probably a trivial question. I have a collection "CellList" which has a few properties I would like to bind to a ToolTip so when I hover over a label information from the current instance of CellList is displayed. How do I do that? I understand simple binding and this maybe simple binding too but I can't wrap my head around it. Below is my XAML for the label. Could someone explain to me how I can accomplish this.
<HierarchicalDataTemplate>
<ListBox ItemsSource="{Binding CellList}">
<ListBox.ItemTemplate>
<DataTemplate>
<Label Content=" " Height="20" Width="15" Background="{Binding Path=ExptNameBkg, Converter={StaticResource ExptNameToBrushConverter}}" BorderBrush="Black" BorderThickness="1" >
</Label>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</HierarchicalDataTemplate>
Thanks.
The tricky thing about ToolTips is that a ToolTip is an object you associate with a control, and not part of the control's visual tree. So you can't populate it the way you'd populate things in the visual tree, e.g.:
<TextBox.ToolTip>
<StackPanel>
...put bound controls here
</StackPanel>
</TextBox.ToolTip>
Instead, what you have to do is create a specific instance of a ToolTip, and assign it a style that sets its DataContext (very important; that's how you can bind to the properties of the data source of its "placement target," i.e. the control that's displaying the tooltip) and its Template. Then put the visual tree of the ToolTip, including bindings, into the template. Finally, reference the ToolTip in your control.
So, here's a TextBox whose Binding does validation:
<TextBox ToolTip="{StaticResource ErrorToolTip}">
<TextBox.Text>
<Binding Source="SourceProperty">
<Binding.ValidationRules>
<DataErrorValidationRule/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
It uses this ToolTip:
<ToolTip x:Key="ErrorToolTip" Style="{StaticResource ErrorToolTipStyle}"/>
And the ToolTip uses this style, which gets its content from the ValidationError property of the TextBox's binding source:
<Style x:Key="ErrorToolTipStyle" TargetType="{x:Type ToolTip}">
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="HasDropShadow" Value="True"/>
<Setter Property="DataContext" Value="{Binding Path=PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToolTip">
<Border
Name="Border"
BorderThickness="1"
BorderBrush="LightGray">
<StackPanel Orientation="Vertical">
<Label Background="Firebrick" Foreground="White" FontWeight="Bold" Margin="4">Validation error</Label>
<TextBlock Margin="10" Text="{Binding ValidationError}"/>
</StackPanel>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="HasDropShadow" Value="true">
<Setter TargetName="Border" Property="CornerRadius" Value="4"/>
<Setter TargetName="Border" Property="SnapsToDevicePixels" Value="true"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I'm not certain of this, but I think that the only part of the above that actually has to be set in the style is the DataTrigger setting the DataContext; I think most everything else could just be explicitly set in the ToolTip's visual tree. But I'm probably not thinking of something important.
<Label Content={Binding Path=Id} ToolTip={Binding Path=Name}/>
just try this
Here's a kaxaml-ready example that includes a tooltip that is a little more elaborate than just text:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<XmlDataProvider x:Key="CharacterData">
<x:XData>
<Data xmlns="">
<Character First="Bart" Last="Simpson" Background="LightGreen" />
<Character First="Homer" Last="Simpson" Background="LightBlue" />
<Character First="Lisa" Last="Simpson" Background="Pink" />
<Character First="Maggie" Last="Simpson" Background="Yellow" />
<Character First="Marge" Last="Simpson" Background="PapayaWhip" />
</Data>
</x:XData>
</XmlDataProvider>
<ToolTip x:Key="ElaborateToolTip">
<Grid Margin="5">
<Rectangle RadiusX="6" RadiusY="6" Fill="{Binding XPath=#Background}" />
<StackPanel Orientation="Horizontal" Margin="10">
<TextBlock Text="{Binding XPath=#First}" Margin="0,0,6,0" />
<TextBlock Text="{Binding XPath=#Last}" />
</StackPanel>
</Grid>
</ToolTip>
</Page.Resources>
<ListBox ItemsSource="{Binding Source={StaticResource CharacterData}, XPath=Data/Character}">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="ToolTip" Value="{StaticResource ElaborateToolTip}" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding XPath=#First}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Page>

How can I set the minimum size of a expander control in WPF?

How can I set expander to show some content it encloses even in collapsed state ? I have the following code snippet, can anyone point changes to this code ?
<Window x:Class="UI2.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="358" Width="300">
<TabControl>
<TabItem Header="Buga Buga">
<StackPanel>
<Expander ClipToBounds="False">
<ListBox Name="lstProcesses"
MinHeight="60">
</ListBox>
</Expander>
</StackPanel>
</TabItem>
</TabControl>
Thanks
It doesn't sound like Expander is the control you should be using for this scenario. Expander has a header, and content, like this:
<Expander Header="Visible all the time">
<TextBlock Text="Hidden until expanded" />
</Expander>
It sounds to me like you want a control that's set to a specific height some of the time, and unrestrained at other times.
I think you could achieve this by binding a ToggleButton (which Expander uses too, internally) to the MaxHeight property of your ListBox.
Try something like this in Kaxaml:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:diag="clr-namespace:System.Diagnostics;assembly=System">
<Page.Resources>
<!-- A way of getting some test data in Kaxaml -->
<ObjectDataProvider x:Key="Processes"
MethodName="GetProcesses"
ObjectType="{x:Type diag:Process}" />
</Page.Resources>
<StackPanel>
<ToggleButton Name="Expand" Content="Expand" />
<ListBox Name="lstProcesses"
ItemsSource="{Binding Source={StaticResource Processes}}"
DisplayMemberPath="ProcessName">
<ListBox.Style>
<Style TargetType="ListBox">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=Expand, Path=IsChecked}"
Value="False">
<Setter Property="MaxHeight" Value="60" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.Style>
</ListBox>
</StackPanel>
</Page>
Here's a quick example of how to the Collapsed text (the Header) to the selected item in the listbox contained within the expander:
<Expander ClipToBounds="False">
<ListBox Name="lstProcesses"
MinHeight="60">
</ListBox>
<Expander.Header>
<TextBlock Text="{Binding SelectedItem, ElementName=lstProcesses}"/>
</Expander.Header>
</Expander>

Resources