Says I have a list of 10 items someList, I will show them on my page via itemsControl like below:
<ItemsControl DataContext="{Binding [someViewModel]}"
BorderBrush="Black"
ItemSource="{Binding someList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderThickness="1" Background="Green">
<StackPanel MouseDown="{Binding Path=DataContext.someCommand,
RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type ItemsControl}}}"
Command Parameter="{Binding someID}">
<TextBlock Text="{Binding something}">
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I do able to trigger someCommand method and I do able to pass in someID as input parameter. Now I'm wondering how to update the stackPanel background color, making it looks like "selected". Meaning now all item will have a green background, when I click on one of the stackpanel, that stackpanel should change background to red and change others back to green
If you want to use ItemsControl you can change ItemTemplate to RadioButton with custom ControlTemplate that will include Border which Background would change to Red when IsChecked == true:
<ItemsControl DataContext="{Binding [someViewModel]}" BorderBrush="Black" ItemSource="{Binding someList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<RadioButton Content="{Binding something}" GroupName="radioGroup">
<RadioButton.Template>
<ControlTemplate TargetType="{x:Type RadioButton}">
<Border Background="Green" x:Name="PART_Border">
<ContentPresenter/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="PART_Border" Property="Background" Value="Red"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</RadioButton.Template>
</RadioButton>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
However I don't see a reason why you cannot use ListBox with SelectionMode=Single (default value) and change Template of ListBoxItem:
<ListBox DataContext="{Binding [someViewModel]}" BorderBrush="Black" ItemSource="{Binding someList}">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border Background="Green" x:Name="PART_Border">
<ContentPresenter/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="PART_Border" Property="Background" Value="Red"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
or even do something like this, without changing Template:
<ListBox DataContext="{Binding [someViewModel]}" BorderBrush="Black" ItemSource="{Binding someList}">
<ListBox.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Red"/>
</ListBox.Resources>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Background" Value="Green"/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
In WPF it's generally much easier to pick a control that has functionality that you need and style it to look like you want then do this the other way round
why not do something like this
<DataTemplate>
<Border BorderThickness="1" Background="Green" x:Name="MyBorder">
<StackPanel MouseDown="{Binding Path=DataContext.someCommand,
RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type ItemsControl}}}"
Command Parameter="{Binding someID}">
<TextBlock Text="{Binding something}">
</StackPanel>
</Border>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=IsSelected}" Value="true">
<Setter TargetName="MyBorder" Property="Background" Value="Black" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
Related
I am having a strange issue. I am not sure if this is a bug, or if I am simply misunderstanding something as I am fairly new to WPF (Probably the latter).
In my project, I have a ListView that displays items in a similar fashion to that seen of Windows Explorer using Icon view. I have outlined a control template that consists of a an Image element, and a TextBlock element below it. My goal is to adjust the maximum height of the TextBlock when the ListViewItem is selected. This is so the name of the Items will adjust from being trimmed with an ellipsis to showing the full name of the item.
When the item is selected however, instead of adjusting the maximum height of only the selected item's TextBlock, it adjusts all TextBlocks for each item whether it is actively selected or not.
I have researched for an answer, but have not found anything similar to this particular issue. This link is a similar concept, but without my problem.
WPF - ListView Item on Selected change Font size
Some of my other methods have consisted of one ControlTemplate with triggers for the style changes, or ItemContainerStyle instead of explicitly a ControlTemplate, which all seemed to give the same undesired result.
How can I achieve this functionality? Is it possible with ControlTemplate?
Here is some of my XAML code:
ListView
<ListView x:Name="ItemViewer">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Margin="10"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="Margin" Value="10"/>
<Setter Property="Template" Value="{StaticResource ListViewItemNormal}"/>
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="True"/>
<Condition Property="Selector.IsSelectionActive" Value="True"/>
</MultiTrigger.Conditions>
<Setter Property="Template" Value="{StaticResource ListViewItemSelected}"/>
</MultiTrigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
</ListView>
ControlTemplates
<ControlTemplate x:Key="ListViewItemNormal" TargetType="{x:Type ListViewItem}">
<Border x:Name="ItemBoxBorder" Background="Transparent">
<Grid HorizontalAlignment="Left" MinHeight="90"
Margin="5"
MaxWidth="90"
Width="90"
x:Name="ItemBox">
<StackPanel>
<Image HorizontalAlignment="Center"
VerticalAlignment="Top"
Source="{StaticResource NewImage}"
Width="64" Height="64"/>
<TextBlock x:Name="ItemDescription"
Text="{Binding Path=Name}"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
TextWrapping="Wrap"
MaxWidth="90"
MaxHeight="30"
TextTrimming="CharacterEllipsis"/>
</StackPanel>
<Grid.ToolTip>
<ToolTip Content="{Binding Path=Name}"/>
</Grid.ToolTip>
</Grid>
</Border>
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="False"/>
<Condition Property="IsMouseOver" Value="True"/>
</MultiTrigger.Conditions>
<Setter TargetName="ItemBoxBorder" Property="Background" Value="{StaticResource HighlightMouseHoverColorBrush}"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="ListViewItemSelected" TargetType="{x:Type ListViewItem}">
<Border x:Name="ItemBoxBorder" Background="{StaticResource SelectedItemBrush}"
BorderBrush="{StaticResource HighlightBorderColorBrush}"
BorderThickness="1">
<Grid HorizontalAlignment="Left" MinHeight="90"
Margin="5"
MaxWidth="90"
Width="90"
x:Name="ItemBox">
<StackPanel>
<Image HorizontalAlignment="Center"
VerticalAlignment="Top"
Source="{StaticResource NewImage}"
Width="64" Height="64"/>
<TextBlock x:Name="ItemDescription"
Text="{Binding Path=Name}"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
TextWrapping="Wrap"
MaxWidth="90"
MaxHeight="125"
TextTrimming="CharacterEllipsis"/>
</StackPanel>
<Grid.ToolTip>
<ToolTip Content="{Binding Path=Name}"/>
</Grid.ToolTip>
</Grid>
</Border>
</ControlTemplate>
EDIT
Here is an example of the issue with ms_dos's implementation.
This image shows I have the item with a short description selected. This is the height all items should remain if they are not selected.
In this image, you'll see the item with the long description is selected. However, both items extend their height, but only the selected one should grow.
You don't need two separate control templates for this. Just take the ItemContainerStyle property of the ListView and use a control template like this:
<ListView x:Name="ItemViewer">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Margin="10" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<Border x:Name="ItemBoxBorder"
Background="Green"
BorderThickness="1"
VerticalAlignment="Top">
<Grid HorizontalAlignment="Left"
MinHeight="90"
Margin="5"
MaxWidth="90"
Width="90"
x:Name="ItemBox">
<StackPanel>
<Image HorizontalAlignment="Center"
VerticalAlignment="Top"
Width="64"
Height="64" />
<TextBlock x:Name="ItemDescription"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
TextWrapping="Wrap"
Text="{Binding}"
MaxWidth="90"
MaxHeight="125"
TextTrimming="CharacterEllipsis" />
</StackPanel>
<Grid.ToolTip>
<ToolTip Content="{Binding Path=Name}" />
</Grid.ToolTip>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected"
Value="true">
<Setter TargetName="ItemBoxBorder"
Property="Background"
Value="Red" />
<Setter TargetName="ItemDescription"
Property="TextElement.FontSize"
Value="20" />
<Setter TargetName="ItemBoxBorder"
Property="Height"
Value="135" />
</Trigger>
<Trigger Property="IsSelected"
Value="false">
<Setter TargetName="ItemBoxBorder"
Property="Height"
Value="90" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>
Take a look at the ControlTemplate.Triggers section. Basically you use the Trigger property to control which property the trigger should handle... in our case the IsSelected from the ListView. And with the Setter you define the property and the value for the changes of the ListViewItem control. The TargetName of the Setter refers to the x:Name of the control which you define in the ControlTemplate section.
I hope this example helps you with your problem!
Greets
ms_dos
I have this code:
<GroupBox Grid.Column="1" BorderThickness="0,0,0,0" HorizontalAlignment="Right">
<ItemsControl FontWeight="Normal"
ItemsSource="{Binding Path=AvailableTipologieDifficolta}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<RadioButton
Content="{Binding Path=DisplayName}"
IsChecked="{Binding Path=IsSelected}"
GroupName="Feedback"
Margin="10,3.5"
Style="{StaticResource RadioButtonTemplate}"
/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</GroupBox>
This is the style of RadioButton:
<Style TargetType="RadioButton" x:Key="RadioButtonTemplate">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="RadioButton">
<RadioButton Foreground="White" FontSize="20">
<ContentPresenter/>
</RadioButton>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
So when I try to run my code I have this:
o Opzione 1
o Opzione 2
I can to select every option but it is not possible. If I delete this code Style="{StaticResource RadioButtonTemplate}" I can to select one option.
Can we help me?
It's because you wrap RadioButton in RadioButton when you create template like that. Inner RadioButton is not linked to outer RadioButton. You don't need to change template for what you want to do just use 2 Setters for Foreground and FontSize
<Style TargetType="RadioButton" x:Key="RadioButtonTemplate">
<Setter Property="Foreground" Value="White"/>
<Setter Property="FontSize" Value="20"/>
</Style>
I am working on a chat program, and I would like to have a single line separate every line of text.
Here is the XAML I am using:
<ScrollViewer Grid.Row="0" Name="ScrollBar">
<ListView HorizontalContentAlignment="Stretch"
BorderThickness="0"
IsTabStop="False"
Name="AllItems"
Background="#E4E4E4"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
PreviewMouseWheel="AllItems_PreviewMouseWheel"
ItemsSource="{Binding Messages}">
<ListView.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Black"
BorderThickness="0, 1, 0, 0">
<TextBlock
FontSize="16"
TextWrapping="Wrap"
FontFamily="Arial"
Margin="0"
Initialized="ChatLine_Initialized"
VerticalAlignment="Center" />
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ScrollViewer>
I'm also setting the background of each line in alternating colors (this is an event handler for TextBlock's Initialize event):
static int s_curr;
void ChatLine_Initialized(object sender, EventArgs e)
{
int curr = Interlocked.Increment(ref s_curr);
if ((curr % 2) == 0)
((TextBlock)sender).Background = (SolidColorBrush)(new BrushConverter().ConvertFrom("#C8C8C8"));
else
((TextBlock)sender).Background = (SolidColorBrush)(new BrushConverter().ConvertFrom("#E4E4E4"));
}
The problem I'm running into is that the darker lines do not fill down to the border.
For example, here is how it renders:
How do I get the darker background to fill down to the border line?
Remove the border of your textblock and apply a style for the ListBox Items, this works,
<Grid>
<ScrollViewer Grid.Row="0" Name="ScrollBar">
<ListView HorizontalContentAlignment="Stretch"
BorderThickness="0"
IsTabStop="False"
Name="AllItems"
Background="#E4E4E4"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ItemsSource="{Binding Messages}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<Border Name="Border" BorderBrush="Black" BorderThickness="1">
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock
FontSize="16"
TextWrapping="Wrap"
FontFamily="Arial"
Text="{Binding Name}"
Initialized="ChatLine_Initialized"
/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ScrollViewer>
</Grid>
Output:
There's no need to create a ListView wrapped in a ScrollViewer and then set each alternate row a different color. A DataGrid has all this functionality built in.
This can be tweaked, but is styled to represent your screen-shot:
<DataGrid HorizontalContentAlignment="Stretch"
BorderThickness="0"
IsTabStop="False"
Name="AllItems"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ItemsSource="{Binding Messages}"
AlternationCount="2"
HeadersVisibility="None">
<DataGrid.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Foreground" Value="Black" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{x:Null}" />
<Setter Property="BorderBrush" Value="{x:Null}" />
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.CellStyle>
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}">
<Style.Triggers>
<Trigger Property="AlternationIndex" Value="0">
<Setter Property="Background" Value="#E4E4E4" />
</Trigger>
<Trigger Property="AlternationIndex" Value="1">
<Setter Property="Background" Value="#C8C8C8" />
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
</DataGrid>
I am try to list some data in WPF listbox control. It is the first time I am using DataTemplate in WPF. Everything is working fine except when there is no data it is not showing 'No items to display'. Below is my code.
<ListBox Name="itemsCtrl" Background="#FFE5E5E5" BorderBrush="{x:Null}" SelectionChanged="itemsCtrl_SelectionChanged" Style="{StaticResource ListStyle}">
<ListBox.Resources>
<!-- Set SelectedItem Background here -->
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="#C2C2C2"/>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsMouseOver,
RelativeSource={RelativeSource
Self}}"
Value="True">
<Setter Property="Background"
Value="#C2C2C2" />
</DataTrigger>
</Style.Triggers>
</Style>
<Style TargetType="ListBox" x:Key="ListStyle" BasedOn="{StaticResource {x:Type ListBox}}">
<Style.Triggers>
<DataTrigger
Binding="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=Items.Count}"
Value="0"
>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<TextBlock>No items to display</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Cursor="Hand" Name="hoverDataTemplate" Orientation="Horizontal" Width="370" VerticalAlignment="Top" Height="40" HorizontalAlignment="Left" >
<Label VerticalContentAlignment="Center" HorizontalAlignment="Left" Padding="15,5,5,5" Width="330" Content="{Binding Path=EVENT_TITLE}" FontSize="12"/>
<Image Height="28" Source="/pr;component/Images/black_next.png" Stretch="Fill" Width="28" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And I am binding data source as shown below.
itemsCtrl.ItemsSource = dao.SelectDataTable(cmd).DefaultView;
When I set the style property of ListBox as ListStyle it is throwing an error
'Provide value on 'System.Windows.StaticResourceExtension' threw an exception.' Line number '292' and line position '22'.
Can anybody point out how to make it correct?
Thanks in advance.
i have used below code and it's work fine
my xaml code
<ListBox Grid.ColumnSpan="2" Grid.Row="1" Height="32" HorizontalAlignment="Left" Margin="160,2,0,0" Name="listBox1" VerticalAlignment="Top" Width="120" Style="{StaticResource Dhaval}"/>
Style look like
<Style x:Key="Dhaval" TargetType="{x:Type ListBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Items.Count}" Value="0">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<TextBlock>No items to display</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
If I have a WPF ListBox which has a basic ItemTemplate that contains a custom user control, how can I tell the user control in the DataTemplate to change its visual state when its selected in the ListBox?
Thanks a lot for any help you can give
You can style the ListBoxItem to trigger on the IsSelected property. Here's an example:
ListBoxItem ControlTemplate Example
and then you use it like this:
<ListBox ItemContainerStyle="{StaticResource yourListBoxItemStyle}">
or directly in the ListBox itself:
<ListBox.ItemContainerStyle>
<Style TargetType=”ListBoxItem”>
...
</Style>
</ListBox.ItemContainerStyle>
Edit:
Here is a complete example with both an ItemTemplate and an ItemContainerStyle that puts a semi-opaque layer on top of the selected item.
<Grid>
<Grid.Resources>
<x:Array Type="sys:String" x:Key="sampleData">
<sys:String>Red</sys:String>
<sys:String>Green</sys:String>
<sys:String>Blue</sys:String>
</x:Array>
<DataTemplate x:Key="listBoxItem">
<Rectangle Fill="{Binding}" Width="100" Height="100"/>
</DataTemplate>
<Style TargetType="ListBoxItem" x:Key="listBoxItemStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Grid>
<ContentPresenter />
<Rectangle x:Name="Rectangle" Fill="Black" Opacity="0"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="Rectangle" Property="Opacity"
Value="0.5"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<ListBox
ItemsSource="{StaticResource sampleData}"
ItemTemplate="{StaticResource listBoxItem}"
ItemContainerStyle="{StaticResource listBoxItemStyle}"
/>
</Grid>
Edit
After a comment, here is the version using a "unified" template:
<Style TargetType="ListBoxItem" x:Key="listBoxItemStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Grid>
<Rectangle Name="Rectangle" Fill="{Binding}" Width="100" Height="100" Opacity="1"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="Rectangle" Property="Opacity"
Value="0.5"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>