Change listbox item style when selected in WPF - c#

I'm not entirely sure what I'm doing incorrect but it appears that my style trigger is not being recognized. I want to change the color of the Stroke when the listbox item is selected.
<ListBox ItemsSource="{Binding CityList}" DisplayMemberPath="Name" SelectionMode="Extended"
VirtualizingPanel.IsVirtualizing="true"
VirtualizingPanel.VirtualizationMode="Recycling"
Background="Brown">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Canvas.Left" Value="{Binding Longitude, Converter={StaticResource longValueConverter}, ConverterParameter={StaticResource mapWidth}}"/>
<Setter Property="Canvas.Top" Value="{Binding Latitude, Converter={StaticResource latValueConverter}, ConverterParameter={StaticResource mapHeight}}"/>
<Setter Property="BorderThickness" Value="3" />
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid>
<Ellipse x:Name="indicator"
Fill="#FF000000"
Height="10"
Width="10"
Stroke="Transparent"
StrokeThickness="2"/>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="indicator" Property="Stroke" Value="Red"/>
</Trigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<Canvas IsItemsHost="True"
Width="{StaticResource mapWidth}"
Height="{StaticResource mapHeight}"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>

You can't use TargetName in a Style Setter.
Instead of setting the ContentTemplate property, you may set the Template property and add the Trigger to the ControlTemplate.Triggers collection:
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Grid>
<Ellipse x:Name="indicator"
Fill="#FF000000"
Height="10"
Width="10"
Stroke="Transparent"
StrokeThickness="2"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="indicator" Property="Stroke" Value="Red"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
You may also add a ContentPresenter to the Grid in the ControlTemplate, which would display the elements of the ItemTemplate (if you later decide to declare one).

Related

How do I prevent switching between items using arrows in ListBox?

There is a ListBox in which there are several ListBoxItems. I want to move items using the arrows (up, down, left, right). When I add one element and then select it, it moves wonderfully, but when there are several elements, it turns out that when you click the arrows, they jump from one element to another and it turns out that I start moving another element. How can I prevent switching between elements using arrows? Attaching the code:
<ListBox x:Name="drawing"
Grid.Row="0"
ItemsSource="{Binding Path=Figures}"
SelectedItem="{Binding Path=SelectedFigure_M}"
SelectionMode="Single"
Background="Transparent"
Height="{Binding HeightDrawing}"
Width="{Binding WidthDrawing}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
MouseMove="drawing_MouseMove"
MouseLeftButtonDown="drawing_MouseLeftButtonDown"
MouseLeftButtonUp="drawing_MouseLeftButtonUp"
PreviewMouseWheel="drawing_MouseWheel"
KeyDown="drawing_KeyDown"
SelectionChanged="drawing_SelectionChanged">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplateSelector>
<local:FigureTemplateSelector EllipseTemplate="{StaticResource EllipseTemplate}"
LineTemplate="{StaticResource LineTemplate}"
RectangleTemplate="{StaticResource RectangleTemplate}"
TextTemplate="{StaticResource TextTemplate}"/>
</ListBox.ItemTemplateSelector>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Canvas.Left"
Value="{Binding X}" />
<Setter Property="Canvas.Top"
Value="{Binding Y}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border Name="Border"
BorderThickness="1"
Padding="1">
<ContentPresenter Name="Content" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected"
Value="true">
<Setter TargetName="Border"
Property="BorderBrush"
Value="Transparent" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
I answer my own question: First, you must prohibit switching between elements using the up, down, left, and right arrows. Required in the ListBox.ItemContainerStyle add a Setter:
<Setter Property="KeyboardNavigation.DirectionalNavigation" Value="None" />
Second: Required in the ListBox.ItemContainerStyle add a Setter that disables the IsTabStop function:
<Setter Property="IsTabStop" Value="False" />
The full code will look like this:
<ListBox x:Name="drawing"
Grid.Row="0"
ItemsSource="{Binding Path=Figures}"
SelectedItem="{Binding Path=SelectedFigure_M}"
SelectionMode="Single"
Background="Transparent"
Height="{Binding HeightDrawing}"
Width="{Binding WidthDrawing}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
MouseMove="drawing_MouseMove"
MouseLeftButtonDown="drawing_MouseLeftButtonDown"
MouseLeftButtonUp="drawing_MouseLeftButtonUp"
PreviewMouseWheel="drawing_MouseWheel"
KeyDown="drawing_KeyDown"
SelectionChanged="drawing_SelectionChanged">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplateSelector>
<local:FigureTemplateSelector EllipseTemplate="{StaticResource EllipseTemplate}"
LineTemplate="{StaticResource LineTemplate}"
RectangleTemplate="{StaticResource RectangleTemplate}"
TextTemplate="{StaticResource TextTemplate}"/>
</ListBox.ItemTemplateSelector>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Canvas.Left"
Value="{Binding X}" />
<Setter Property="Canvas.Top"
Value="{Binding Y}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border Name="Border"
BorderThickness="0.5"
Padding="1">
<ContentPresenter Name="Content" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected"
Value="true">
<Setter TargetName="Border"
Property="BorderBrush"
Value="Transparent" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="IsTabStop"
Value="False" />
<Setter Property="KeyboardNavigation.DirectionalNavigation"
Value="None" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
Source

How can I change background behind border (ListView.ItemTemplete->datatemplete) when I hover or click?

My problem is when I click or hover in ListViewItem which also show the silver background:
enter image description here
this is my code xaml:
<ListView
Margin="0,30,0,0"
Height="600"
ScrollViewer.VerticalScrollBarVisibility="Hidden"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
Name="ListViewFC" ItemsSource="{Binding ListWords, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding SelectedItem, Mode=TwoWay}" >
<ListView.ItemTemplate>
<DataTemplate>
<Border
Width="340"
x:Name="Border"
Height="80"
Background="Pink"
CornerRadius="15"
BorderThickness="1"
>
<Grid>
<TextBlock
VerticalAlignment="Center"
x:Name="txtContent"
Foreground="Black"
Text="{Binding Question1,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}"
TextWrapping="NoWrap"
Margin="30 0 0 0"
FontSize="15"
/>
</Grid>
</Border>
<DataTemplate.Triggers>
<DataTrigger
Binding="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ListViewItem}}, Path=IsSelected}" Value="True">
<Setter TargetName="Border" Property="Background" Value="White" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I want that When I hover or click It don't show the silver background.
pls, help me .Thanks.
Add this inside your ListView:
<ListView.Resources>
<Style BasedOn="{StaticResource TextBlockStyle}" TargetType="{x:Type TextBlock}" />
<Style BasedOn="{StaticResource ListViewItemStyle}" TargetType="{x:Type ListViewItem}" />
</ListView.Resources>
Then add this outside of your ListView (this displays a background of gold on hover):
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Gold" />
</Trigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
The default ControlTemplate of the ListView contains a Border with Padding of 2X. Hence you have to change its template something like this
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>

Collapse GroupBox border without collapsing content

Is it possible to collapse the border of a GroupBox control in XAML (i.e. bind to a property in the VM) without also collapsing the content?
I don't just want to remove the border, which can be achieved by setting BorderThickness to 0 and Header to an empty string. I also want the GroupBox content to stretch out over where the border was.
<DataTemplate DataType="{x:Type config:ElementGroup}">
<DataTemplate.Resources>
<Style TargetType="{x:Type GroupBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=HideBorder}" Value="True">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
<Setter Property="Foreground" Value="{StaticResource TextColor}" />
<Setter Property="Header" Value="{Binding Path=ItemLabel}" />
<Setter Property="Margin" Value="5,0,5,0" />
</Style>
</DataTemplate.Resources>
<GroupBox>
<ItemsControl ItemsSource="{Binding Path=ElementList}" Visibility="Visible">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="{Binding Path=Columns}" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</GroupBox>
</DataTemplate>
Change your GroupBox Style to this:
<Style TargetType="{x:Type GroupBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=HideBorder}" Value="True">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GroupBox">
<ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
ContentStringFormat="{TemplateBinding ContentStringFormat}"
Margin="{TemplateBinding Padding}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
<Setter Property="Foreground" Value="{StaticResource TextColor}" />
<Setter Property="Header" Value="{Binding Path=ItemLabel}" />
<Setter Property="Margin" Value="5,0,5,0" />
</Style>
Collapsing a GroupBox, i.e. setting its Visibility property to Hidden or Collapse, will also collapse its Content.
If you don't want this, you could define another ItemsControl that you display when the GroupBox gets collapsed:
<DataTemplate DataType="{x:Type config:ElementGroup}">
<DataTemplate.Resources>
<Style TargetType="{x:Type GroupBox}">
<Setter Property="Foreground" Value="{StaticResource TextColor}" />
<Setter Property="Header" Value="{Binding Path=ItemLabel}" />
<Setter Property="Margin" Value="5,0,5,0" />
</Style>
</DataTemplate.Resources>
<Grid>
<GroupBox x:Name="gb">
<ItemsControl ItemsSource="{Binding Path=ElementList}" Visibility="Visible">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="{Binding Path=Columns}" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</GroupBox>
<ItemsControl x:Name="ic" ItemsSource="{Binding Path=ElementList}" Visibility="Collapsed">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="{Binding Path=Columns}" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=HideBorder}" Value="True">
<Setter TargetName="gb" Property="Visibility" Value="Collapsed" />
<Setter TargetName="ic" Property="Visibility" Value="Visible" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>

WPF ItemsControl and Togglebuttons weird behaviour

I've been working on a WPF application but encountered some weird behaviour when using ItemsControl to display a list of togglebuttons with binding. It works just fine when it is displaying a collection of 1 element, but when I have two elements it behaves very strange. It will not show the image of both togglebuttons at once if they are in the same state (i.e. toggled on).
The relevant XAML. I have checked that the property behind is updated correctly, but let me know if there is any code that is needed.
<ItemsControl x:Name="ServiceItemsControl" Grid.Row="0" ItemsSource="{Binding DraftMessage.Services}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ToggleButton IsChecked="{Binding Path=Selected}">
<ToggleButton.Style>
<Style TargetType="ToggleButton">
<Setter Property="Focusable" Value="False"/>
<!--Setter Property="BorderThickness" Value="0"/-->
<Setter Property="Opacity" Value="1"/>
<Setter Property="Content">
<Setter.Value>
<Image Source="{Binding Path=Service.OtherLogo}" Width="25" Height="25"/>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content">
<Setter.Value>
<Image Source="{Binding Path=Service.Logo}" Width="25" Height="25"/>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
You need to use a DataTrigger on the Image to change its Source property when the ToggleButton.IsChecked value is changed instead. Try this:
<DataTemplate>
<ToggleButton IsChecked="{Binding Path=IsSelected}">
<Image Width="25" Height="25">
<Image.Style>
<Style TargetType="{x:Type Image}">
<Setter Property="Source" Value="{Binding Service.OtherLogo}" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked,
RelativeSource={RelativeSource AncestorType={x:Type
ToggleButton}}}" Value="True">
<Setter Property="Source" Value="{Binding Service.Logo}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
<ToggleButton.Style>
<Style TargetType="ToggleButton">
<Setter Property="Focusable" Value="False"/>
<!--Setter Property="BorderThickness" Value="0"/-->
<Setter Property="Opacity" Value="1"/>
</Style>
</ToggleButton.Style>
</ToggleButton>
</DataTemplate>

ToggleButton style not working when in treeview

I have a treeview with buckets and parts. Everything looks great except one feature. A property on bucket (bool IsEditable) allows the user to toggle editing on or off within the tree view for that node. But for some reason when wpf displays the collection of buckets in the treeview the togglebuttons do not show the proper text
Here is my xaml:
<Style TargetType="{x:Type ToggleButton}" x:Key="Editor">
<Style.Triggers>
<Trigger Property="IsChecked" Value="False">
<Setter Property="Content">
<Setter.Value>
<TextBlock Text="Edit"/>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content">
<Setter.Value>
<TextBlock Text="Done"/>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
<DataTemplate x:Key="HierarchialItemTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding BucketQty, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock Text=" "/>
<TextBlock Text="{Binding PartNum}"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="DisplayBucket">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Sequence}"/>
<TextBlock Text=" "/>
<TextBlock Text="{Binding Description}"/>
<ToggleButton IsChecked="{Binding IsEditable}" Width="25" Style="{StaticResource Editor}"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="EditBucket">
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding Sequence}"/>
<TextBlock Text=" "/>
<TextBox Text="{Binding Description}"/>
<ToggleButton IsChecked="{Binding IsEditable}" Width="25" Style="{StaticResource Editor}"/>
</StackPanel>
</DataTemplate>
<HierarchicalDataTemplate x:Key="TreeTemplate"
DataType="{x:Type domain:Bucket}"
ItemsSource="{Binding Parts}"
ItemTemplate="{StaticResource HierarchialItemTemplate}"
>
<ContentPresenter Content="{Binding}"
Style="{DynamicResource TreeNodeStyle}"/>
</HierarchicalDataTemplate>
<Style TargetType="{x:Type ContentPresenter}" x:Key="TreeNodeStyle">
<Setter Property="ContentTemplate" Value="{StaticResource DisplayBucket}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsEditable}" Value="True">
<Setter Property="ContentTemplate" Value="{StaticResource EditBucket}"/>
</DataTrigger>
</Style.Triggers>
</Style>
The above is window.resources. In the Grid is
<TreeView x:Name="Buckets"
ItemsSource="{Binding Model.Job.Buckets}"
ItemTemplate="{StaticResource TreeTemplate}"
>
So for whatever reason when I add nodes I get a bucket with a toggle button, but the toggle button text only shows up for the last node added. If I click a toggle button, the text disappears out of the previous toggle button and shows up in the one just clicked. The effect is similar to what this person experienced, but I have no idea what the guy was talking about who answered the question ToggleButton Style only works on last ToggleButton.
Any thoughts?
You have couple of options (ordered from least to most dramatic):
1) Content
<Style TargetType="{x:Type ToggleButton}" x:Key="Editor">
<Style.Triggers>
<Trigger Property="IsChecked" Value="False">
<Setter Property="Content" Value="Edit" />
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content" Value="Done" />
</Trigger>
</Style.Triggers>
</Style>
2) ContentTemplate
<Style TargetType="{x:Type ToggleButton}" x:Key="Editor">
<Style.Triggers>
<Trigger Property="IsChecked" Value="False">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="Edit"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="Done"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
3) ControlTemplate
<Style TargetType="{x:Type ToggleButton}" x:Key="Editor">
<Style.Triggers>
<Trigger Property="IsChecked" Value="False">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<TextBlock Text="Edit"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<TextBlock Text="Done"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
The reason why your approach didn't work is that TextBlock control is created only once (i.e. not created as part of template - ControlTemplate or DataTemplate).

Categories