WPF radiobuttons IsHitTestVisible not working - c#

I'm using radiobuttons inside a listbox and cannot disable them.
After searching I found links about IsEnabled and IsHitTestVisible. When I set IsEnabled to false the button and text turns grey however it's still clickable. Setting IsHitTestVisible does nothing to change this. My XAMLcode looks like this:
<ListBox ItemsSource="{Binding Source}" BorderThickness="0" VerticalAlignment="Stretch" Background="Transparent" SelectedItem="{Binding SelectedSource, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" >
<ListBox.ItemTemplate>
<DataTemplate>
<RadioButton IsHitTestVisible="{Binding IsEnabled}" IsEnabled="{Binding IsEnabled}" Margin="0 2 0 0" FontSize="12" FontFamily="Segoe UI Regular" Content="{Binding name}" GroupName="GroupList" >
<RadioButton.Style>
<Style TargetType="{x:Type RadioButton}">
<Setter Property="IsChecked" Value="{Binding Path=IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}}" />
</Style>
</RadioButton.Style>
</RadioButton>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Property in c# that calculates and returns bool.
public bool IsEnabled
{
get
{
IsEnabledCalculate();
return isEnabled;
}
}
Any ideas about how to disable selection?

Using IsHitTestVisible on a RadioButton in ListBox was a good start. This way, when you click the RadioButton, the event goes "through" it and is handled by ListBoxItem (the item gets selected). You can then manipulate IsChecked property by binding it do IsSelected property of the ListBoxItem.
This is however still not enough to achieve waht you want. First, you're binding your IsEnabled property on the wrong level: the RadioButton. As you noticed, this still allows the ListBoxItem to get selected. So, you need to bind your IsEnabled property to the IsEnabled property of ListBoxItm instead:
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsEnabled" Value="{Binding Path=IsEnabled}"/>
</Style>
</ListBox.ItemContainerStyle>
There still is one minor issue here. When your IsEnabled property is changed in the codebehind, the ListBoxItem will get disabled but the RadioButton will still be checked. To prevent this and uncheck the RadioButton whenever the item gets disabled you can use a DataTrigger:
<DataTemplate>
<RadioButton GroupName="GroupList" IsHitTestVisible="False"
Margin="0 2 0 0" FontSize="12" FontFamily="Segoe UI Regular"
Content="{Binding name}" >
<RadioButton.Style>
<Style TargetType="{x:Type RadioButton}">
<Setter Property="IsChecked" Value="{Binding Path=IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}}" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsEnabled}" Value="False">
<Setter Property="IsChecked" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</RadioButton.Style>
</RadioButton>
</DataTemplate>

Related

ListView with RadioButton in ItemTemplate does not update SelectedItem

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

Not able to display checkboxes for ListViewItems in WPF

I want to display checkboxes alongside text in ListView. I have multiple ListViews in my WPF window, hence I want to specify this behavior as a style in resources. But the checkboxes are not displayed, only the text is. So please, find below my code and suggest edits.
<Window.Resources>
<Style TargetType="ListView" x:Key="ListViewTemplate">
<Setter Property="Background" Value="Transparent"></Setter>
<Setter Property="BorderBrush" Value="Transparent"></Setter>
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding Path=IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}}" Content=""></CheckBox>
<Separator Width="5"></Separator>
<TextBlock Text="{Binding Text}"></TextBlock>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<ListView Grid.Column="1" Grid.Row="3" Grid.ColumnSpan="8" Grid.RowSpan="5" x:Name="listViewDocTypes" Style="{DynamicResource ListViewTemplate}" >
</ListView>
</Grid>
Provide a Text or Width to the Checkbox. Without setting the Text property the length will automatically be "0" if you do not specify its Width.
<CheckBox Content="xyz" Width="1234"/>
The problem was that I was binding data the wrong way.I was using the following code.
ListViewItem item = new ListViewItem();
item.Tag = docType;
item.Text = docType.Text;
listViewDocTypes.Items.Add(item);
The correct way to bind is
listViewDocTypes.ItemsSource = docTypes;

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)

(WPF) How to change button image background in listBox with buttons in each line ?

i have listbox, and the data template is button :
<ListBox x:Name="lbname" ItemsSource="{Binding myCollection}">
<ListBox.ItemTemplate>
<DataTemplate>
<Button x:Name="btnname" Content="{Binding name}" Click="btnname_Click">
<Button.Background>
<ImageBrush ImageSource="/myApplication;component/images/buttons/normal.png"/>
</Button.Background>
</Button>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
i have two image backgroud for this listBox image (normal.png for normal mode, click.png for selected item in listBox)
The listBox view items in list of buttons, the button image background is normally normal.png
my question is how to change the button image background to click.png for selected one and the old selected button retrieve to normal.png
How to change image background for selected item in listBox with buttons in each line ?
hope this clear, please i spend about one day about this issue
can any one help
Thanks
I haven't tested it, but you need some code that looks like this:
<ListBox x:Name="lbname" ItemsSource="{Binding myCollection}">
<ListBox.ItemTemplate>
<DataTemplate>
<Button x:Name="btnname" Click="btnname_Click">
<Grid>
<Image>
<Image.Style>
<Style>
<Setter Property="Image.Source"
Value="/myApplication;component/images/buttons/normal.png" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}}"
Value="True">
<Setter Property="Image.Source"
Value="/myApplication;component/images/buttons/click.png" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
<TextBlock Text="{Binding name}" HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Grid>
</Button>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The idea is to bind directly to the IsSelected property of the ListBoxItem object. This is done using a RelativeSource binding. However, I'm guessing that this code doesn't do what you want... I suggest that you might want to use a ToggleButton instead... something like this:
<ListBox x:Name="lbname" ItemsSource="{Binding myCollection}">
<ListBox.ItemTemplate>
<DataTemplate>
<ToggleButton x:Name="btnname" Click="btnname_Click" IsChecked="{Binding
IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type
ListBoxItem}}}">
<Grid>
<Image>
<Image.Style>
<Style>
<Setter Property="Image.Source"
Value="/myApplication;component/images/buttons/normal.png" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}}"
Value="True">
<Setter Property="Image.Source"
Value="/myApplication;component/images/buttons/click.png" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
<TextBlock Text="{Binding name}" HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Grid>
</ToggleButton>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
if you are using MVVM then make a property in viewModel and bind this to ImageBrush as ImageSource,
when you are selecting value in ListView then get selected record and change image path of this property.
Try using Togglebutton instead of button.Use a trigger to check when the IsChecked property of the toggleButton changes. And based on that change your image.

WPF ListBoxItem IsMouseOver

I have a ListBox, which on mousing over an item shows a delete button for that item. The problem is that the IsMouseOver triggers about 4 pixels into the highlighted item, so when mousing over multiple items, instead of the delete button seeming to move up and down with you, it flickers in the gaps between the items. Is there anyway to make IsMouseOver respond to the whole item?
<ListBox Name="lstLength" ItemsSource="{Binding Source={StaticResource lengths}}">
<ListBox.ItemTemplate>
<DataTemplate>
<DockPanel LastChildFill="True" Height="22">
<Button DockPanel.Dock="Right" Name="btnDelete" Content="X" Tag="{Binding}" Click="DeleteLength" Visibility="Collapsed" />
<TextBlock Text="{Binding}" />
</DockPanel>
<DataTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="btnDelete" Property="Visibility" Value="Visible" />
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Each one of your items will be contained within a ListBoxItem, this is what gives the ~4 pixels between each item. It also provides the highlight and selection styling. You can style the listBoxItem via the ListBox.ItemContainerStyle property. Move your trigger to the item container and it should work as desired.
You could use a DataTrigger directly on the button (or try to apply the same RelativeSource binding in the place it is):
<Style TargetType="{x:Type Button}">
<DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource AncestorType=ListBoxItem}}"
Value="True">
<!-- ... -->
</DataTrigger>
</Style>

Categories