Focus on Button inside ListBoxItem without code - wpf

I have a WPF application with ListBox that display list of items.
Each item has IsChecked property.
I have change the style of the ItemContainerStyle of the list box as follos:
<Style x:Key="OrgListItemStyle" TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<ToggleButton IsChecked="{Binding IsChecked}">
<ContentPresenter />
</ToggleButton>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The problem is that the focus, when navigating with the keyboard, is on the ListBoxItem and not the ToggleButton itself which makes it not intuitive to work with.
How ca I change the focus so it will be right on the button and not the ListBoxItem - preferable not with code.
Thank you,
Ido

You could set Focusable to false for the ListBoxItems in your Style:
<Setter Property="Focusable" Value="False"/>
Note that ListBox has some magic to remember the element that had keyboard focus that won't work if you don't allow the ListBoxItem to be selected.
If you don't want to use the features of the ListBox at all, then you may be better off using a plain ItemsControl rather than a ListBox. You would need to use a DataTemplate rather than a ControlTemplate since there is no container control:
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ToggleButton IsChecked="{Binding IsChecked}" Content="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

Related

Excess border selection in WPF's Lisbox [duplicate]

I have a ListBox in which each item is a StackPanel. The StackPanel consist of an Image and a TextBlock below it:
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="10">
<Image>
<Image.Source>
<BitmapImage UriSource="{Binding Path=ImageFilePath}"/>
</Image.Source>
</Image>
<TextBlock Text="Title" TextAlignment="Center"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
It looks like this:
When the user select an item, I get the default blue rectangle that surround the StackPanel:
Now, I want to make a different border for the selected-item, but I want it to surround only the image.
I know how to make a control template and put a custom border around the ContentPresenter, but this, of course, will surround the whole StackPanel, not only the Image.
I don’t know if making changes to the ContentPresenter is possible, and if it is a good idea at all. If there is other way to achieve the look I want, it will be fine as well.
Right, the ListBox's own ContentPresenter isn't helpful for what you're doing. You want to a) eliminate the ListBox's own selection visuals and b) replace them with something more suitable in the DataTemplate for your items.
The default selection visual is applied by the default template for ListBoxItem. So replace that template. Using a Style in the resources for your ListBox, apply your own control template to ListBoxItem. Not much to it, just present the content and don't provide a selection background. Then you handle the selection visuals with a trigger in your data template, where your image and your label are defined and you can apply changes to one and not the other. The below example works for me.
Note that there's some fiddling with the HorizontalAlignment on the Border element to make it cling to the Image element within it. Also, I wrote a quickie test viewmodel whose Items property is called Items; I assume this is not the name of the collection member you're using to populate your own ListBox.
<ListBox
Margin="8"
ItemsSource="{Binding Items}"
>
<ListBox.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Grid>
<ContentPresenter />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Border
x:Name="HighlightBorder"
BorderThickness="4"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="10"
>
<Border.Style>
<Style TargetType="Border">
<!-- MUST set default BorderBrush via a style, if you set it at all.
As an attribute on the Border tag, it would override the effects of
the trigger below.
-->
<Setter Property="BorderBrush" Value="Transparent" />
</Style>
</Border.Style>
<Image Source="{Binding ImageFilePath}" />
</Border>
</Grid>
<DataTemplate.Triggers>
<DataTrigger
Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListBoxItem}}"
Value="True">
<Setter TargetName="HighlightBorder" Property="BorderBrush" Value="Orange" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

set value for listboxitem templated binding

I have this style:
<Style x:Key="SelectableListBoxItemStyle" TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border Background="Transparent"
BorderBrush="{TemplateBinding BorderBrush}"
CornerRadius="4"
BorderThickness="2"
x:Name="IconBorder"
Margin="4,2,4,2">
<ContentPresenter/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="IconBorder"
Property="BorderBrush"
Value="Blue" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
My problem is that I don't know which property to set on the ListBox, when consuming my style so that the borders of it's ListBoxItems would end up having the desired border brush. I would also like to make this work for the other border brush in my style.
I would like to be able to have two list boxes with this same style but different border colors. I have this for a ListBox:
<ListBox
ItemsSource="{Binding SelectedProduct.Pictures}"
SelectedItem="{Binding SelectedSet, Mode=TwoWay}"
ItemContainerStyle="{StaticResource ResourceKey= SelectableListBoxItemStyle}">
</ListBox>
Update..I tried this:
<ListBox
ItemsSource="{Binding SelectedProduct.Pictures}"
SelectedItem="{Binding SelectedSet, Mode=TwoWay}">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}" BasedOn="{StaticResource SelectableListBoxItemStyle}">
<Setter TargetName="IconBorder" Property="BorderBrush" Value="Green" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
But, I get:
Error 8 TargetName property cannot be set on a Style Setter.
Instead of using a TemplateBinding you should try using a relative source binding.
BorderBrush="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Listbox}},
Path=BorderBrush}"
If you want to have a different border than that defined for the ListBox then you will need to add a brush resource to your ResourceDictionary and apply that instead:
<Listbox.Resources>
<SolidColorBrush x:Key="MyListBoxItemBorderBrush" Color="Red"/>
<Listbox.Resources>
and then in your template:
BorderBrush="{StaticResource MyListBoxItemBorderBrush}"
If you need certain items to have different borders then you need to look at a StyleSelector.
I am not 100% sure, but I think you may need a custom control for that. A least I know you can do it with a custom control!
If you create a custom control, extending from ListBox, that includes this style you've created, you can then create an attached property in it (something like ItemBorderColor) that you could bind to your border's BorderColor (actually, for a selection effect, you may want to create a trigger on you ControlTemplate () that applies that "ItemBorderColor" value to the border's BorderColor based on the "IsSelected" property).
There may be a pure XAML way to do it, but I do not know it....

ComboBoxItem Selection Area Issue

I have a comboBox with a ComboBox.ItemTemplate
<ComboBox>
<ComboxBox.ItemTemplate>
<DataTemplate DataType="{x:Type ViewModel}">
<TextBlock Text="1" />
</DataTemplate>
</ComboxBox.ItemTemplate>
</ComboBox>
The Item renders properly, but when I try to select the ComboxItem, the selection is only available on "1" rest of the Area in the ComboBoxItem is not clickable.
How do I set up the code so the selection can happen on the whole item and not just the Textblock.
Your ComboBox/ComboBoxItem seems to be templated, by default the highlight brush is a deeper blue. If you have access to the templates make sure the content of the ComboBoxItem stretches horizontally.
If the template is bound "correctly" setting the content-alignments may be enough.
<ComboBox.ItemContainerStyle>
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
</Style>
</ComboBox.ItemContainerStyle>

Problem getting custom content in a TabItem visible

I have a custom ItemsControl (WorKArea) that marks all items it has into a WorkSheet instance.
I have a style for the ItemsControl that uses a TabControl to show the content. Every sheet creates a tab. The style is:
<Style TargetType="{x:Type local:WorkArea}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:WorkArea}">
<TabControl ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:WorkArea}}, Path=Items}">
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="Header" Value="{Binding Title}" />
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
So far so good. The "sheets" show up, and the title is properly bound to the Header.
How can I get the tabs showing the content now? Whatever I try, nothing shows up at all for every WorkSheet - the content is always empty. Anyone the proper code?
Your work area should provide a ContentTemplate property and the TabControl should have a TemplateBinding which to it.

ContentPresenter not showing Usercontrol, how come?

I have a ListBox that displays a number of usercontrols that are bound to my questions. This is working fine, however I don't want each of the items in the ListBox to be selectable, as such I created a blank style and applied it to the ItemContainerStyle. This has resulted in my content to disappear and each item is showing blank. Any ideas?
--Xaml--
<ListBox ItemContainerStyle="{StaticResource noSelect}" Name="lbTasks" Height="180"
BorderBrush="#E6E6E6" >
<ListBox.ItemTemplate>
<DataTemplate>
<my:TaskQuestion Question="{Binding Test}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
--Style--
<Style x:Key="noSelect" TargetType="{x:Type ListBoxItem}">
<Setter Property="Margin" Value="2, 2, 2, 0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Am i using the content presenter incorrectly?
Tia, Kohan
Set TargetType for your ControlTemplate in the Style
e. g. <ControlTemplate TargetType="{x:Type ListBoxItem}">

Resources