ListView with RadioButton in ItemTemplate does not update SelectedItem - c#

I have a Listview with RadioButtons inside the ItemTemplate:
<ListView ItemsSource="{Binding }">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<RadioButton IsChecked="{Binding Choice1}" />
<RadioButton IsChecked="{Binding Choice2}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
It is possible to select the current item on the "background". But if I click a RadioButton the SelectedItem is not set.
Desired behavior: the ListViewItem is selected whenever a "childitem" is clicked. Like Outlook when you set a flag, the current mail is selected.
Do I have to bubble up the click event somehow?

This behavior comes from the fact, that the IsKeyboardFocusWithin-Property of the ListViewItem is false in that case. While you are clicking the RadioButton, the RadioButton has the Keyboard-Focus.
Solution
Add a simple trigger like this
<Style TargetType="ListViewItem">
<Style.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="true">
<Setter Property="IsSelected" Value="true" />
</Trigger>
</Style.Triggers>
</Style>
Complete Sample
<ListView ItemsSource="{Binding }">
<ListView.Resources>
<Style TargetType="ListViewItem">
<Style.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="true">
<Setter Property="IsSelected" Value="true" />
</Trigger>
</Style.Triggers>
</Style>
</ListView.Resources>
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<RadioButton IsChecked="{Binding Choice1}" />
<RadioButton IsChecked="{Binding Choice2}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Note
Be sure you choose the right TargetType (ListViewItem, ListBoxItem or TreeViewItem)
Hope this helps

Related

Create a ComboBox containing the values of a checked CheckBoxs

I am creating a list of CheckBoxs and a ComboBox that contains the list of checked checkboxes in WPF MVVM application. I don't know how to bind in text of combobox checked values from checkboxes.
Here is what I have tried:
<ComboBox ItemsSource="{Binding Systems}" Grid.Row="4" Grid.Column="1"
IsEditable="True" IsReadOnly="True" Text="{}">
<ComboBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding TemplateName}" IsChecked="{Binding
IsSystemChecked, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
This should do the trick:
<StackPanel>
<ListView ItemsSource="{Binding Systems}" >
<ListView.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding TemplateName}" IsChecked="{Binding
IsSystemChecked, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ComboBox ItemsSource="{Binding Systems}" DisplayMemberPath="TemplateName" >
<ComboBox.Style>
<Style TargetType="ComboBox">
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="ComboBoxItem" BasedOn="{StaticResource {x:Type ComboBoxItem}}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsSystemChecked}" Value="False">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</Setter.Value>
</Setter>
</Style>
</ComboBox.Style>
</ComboBox>
</StackPanel>
Here there is:
ListView containing a checkbox for each item in Systems which is bound to to the IsSystemChecked property
ComboBox containing all of the items in Systems however if the IsSystemChecked property is false the Visibility is set to Collapsed so it is not displayed
Let me know if you have any issues! Hope this helps.

How can I know if item is selected inside the ItemTemplate?

I have a ListBox that use my custom ItemTemplate. I want to set Visibility property in my TextBlock (inside my template) depending on selected item. I think of doing it using triggers. But how can I know inside my template if current item is selected or not?
<DataTemplate x:Key="myTemplate">
<StackPanel Orientation="Horizontal">
<Image Tag="{Binding priority}" Loaded="SetIconPriority"/>
<Image Tag="{Binding alarm}" Loaded="SetIconAlarm"/>
<!-- I want this TextBlock to be visible only when item is selected -->
<TextBlock Text="{Binding description}"/>
</StackPanel>
</DataTemplate>
edit:
It works, thanks! Code:
<TextBlock Grid.Column="2" Grid.Row="1" Text="{Binding opis}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListBoxItem}}" Value="False">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
Using a RelativeSource binding with AncestorType being ListBoxItem.
<DataTrigger Binding="{Binding IsSelected,
RelativeSource={RelativeSource AncestorType=ListBoxItem}}"
Value="True">
(May want to reverse the logic and Collapse on False instead, avoids the default value Setter)

Change the colour of the particular element in Treeview WPF

I have a Treeview in my WPF application. On the fly, in run time, If the element of the Tree meets certain condition, It should change its Font color from Black To Red.!
XAML
<TreeView Grid.Column="0" Grid.Row="0" HorizontalAlignment="Stretch" Name="treeView1"
VerticalAlignment="Stretch"
SelectedItemChanged="treeView1_SelectedItemChanged" HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Top" BorderThickness="0,0,0,1" BorderBrush="LightGray">
<TreeViewItem Header="Head Tree" ItemsSource="{Binding MainComps}">
<TreeViewItem.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
<Setter Property="FontWeight" Value="Normal" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Bold" />
</Trigger>
<DataTrigger Binding="{Binding IsSelected}" Value="True">
<Setter Property="Foreground" Value="RED" />
</DataTrigger>
</Style.Triggers>
</Style>
</TreeViewItem.ItemContainerStyle>
<TreeViewItem.Resources>
<HierarchicalDataTemplate DataType="{x:Type TextBlock}" ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Head Tree" />
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:MainCompViewModel}" ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Maincompname}" />
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:FeatureViewModel}" ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding FeatureName}" />
</StackPanel>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type local:CompViewModel}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Component}" />
</StackPanel>
</DataTemplate>
</TreeViewItem.Resources>
</TreeViewItem>
</TreeView>
Code behind
private void treeView1_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
if(selected Item meets certain condition)
{
//Change color of tree node
}
}
How can I change the color of particular Node and leave it in the same color SO that when expanded again It should be in RED.
Any help would be appreciated.
You could create a boolean property in the model which is true when the elements meets the condition. Then you bind the Foreground like so:
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=BoolProp}" Value="False">
<Setter Property="Foreground" Value="Blue"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Path=BoolProp}" Value="True">
<Setter Property="Foreground" Value="Red"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>
or with converter:
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="Foreground" Value="{Binding Path=BoolProp, Converter={StaticResource ResourceKey=TheKey}}"/>
</Style>
</TreeView.ItemContainerStyle>
Just change the Foreground:
TreeViewItem ti = (TreeViewItem)treeView1.SelectedItem;
ti.Foreground = Brushes.Red;
That is embedded into the template. You can only change the color by copying the default Aero-Style for the control and changing the hard-coded value.
Or by drilling down the visual tree on-load to change it that way.
To get the default style & tenmplate go through this MSDN
Can also check step wise EXAMPLE from here.

UserControl databinding with a treeview

I have a UserControl which contains a TreeView and a TextBlock:
<TreeView ItemsSource="{Binding FirstGeneration}" AllowDrop="True" Drop="TreeView_Drop" Width="300">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
<Setter Property="FontWeight" Value="Normal" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Normal" />
</Trigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal" >
<Image Source="{Binding Path=Image}" />
<TextBlock Text="{Binding Name}" />
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
<TextBlock Height="23" Name="textBlock1" Text="{Binding= ???}" Width="187" />
When I select an item of the treeview, I want do show some informations contained in the item (eg : the name of the selected item).
My problem is that I don't know how doing this binding, because when I select an item, the setter IsSelected of the item class is called.
Have you a best practice for doing that ?
Have a look at this in MSDN. And also the BindableSelectedItemBehaviour here.

How do I change an image of a node in a WPF treeview when the node is expanded or collapsed?

My Xaml looks like this:
<TreeView Name="mainTree" ItemsSource="{Binding Folders}">
<TreeView.Resources>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
<Style.Triggers>
<!-- ??? -->
</Style.Triggers>
</Style>
<HierarchicalDataTemplate DataType="{x:Type local:FolderNode}" ItemsSource="{Binding Children}" >
<StackPanel Orientation="Horizontal" Name="myPanel">
<Image x:Name="treeImg" Width="16" Height="16" Source="Images/vsfolder_closed.png"/>
<TextBlock Text="{Binding Name}" />
</StackPanel>
<HierarchicalDataTemplate.Triggers>
<!-- ??? -->
</HierarchicalDataTemplate.Triggers>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
Now what I would like is if a treenode is expanded, the image source changes to Images/vsfolder_open.png...
What would be the easiest way to do that?
Thanks in advance!
Add a DataTrigger to the HierarchicalDataTemplate. Since you have two-way binding to the Property IsExpanded in the ViewModel you can bind to it and use TargetName because of the namescope in a DataTemplate.
<HierarchicalDataTemplate.Triggers>
<DataTrigger Binding="{Binding IsExpanded}" Value="True">
<Setter TargetName="treeImg"
Property="Source"
Value="Images/vsfolder_open.png"/>
</DataTrigger>
</HierarchicalDataTemplate.Triggers>

Categories