Styling ListBox with Static Content - xaml

I have a set of static content that I want in a ListBox control.
<ListBox>
<ListBox.Items>
<ListBoxItem>
<Image />
<TextBlock Text="One" />
</ListBoxItem>
<ListBoxItem>
<Image />
<TextBlock Text="Two" />
</ListBoxItem>
<ListBoxItem>
<Image />
<TextBlock Text="Three" />
</ListBoxItem>
</ListBox.Items>
</ListBox>
How do I go about styling this? I know I can style each ListBoxItem individually, and I know how to style when data bound, but how do I style the a listbox item template when using static content like this?

You can define the items as low-level objects and use data-templating, which may not be the same as styles but properties are only set once as well:
<ListBox xmlns:sys="clr-namespace:System;assembly=mscorlib">
<ListBox.Items>
<sys:String>one</sys:String>
<sys:String>two</sys:String>
<sys:String>three</sys:String>
</ListBox.Items>
<ListBox.ItemTemplate>
<DataTemplate>
<!-- "Style" this at will -->
<StackPanel>
<Image />
<TextBlock Text="{Binding}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
(To style the wrapping ListBoxItems you can try using an implicit style defined in the ListBox.Resources)
The following only works in WPF
Add a style to the resources of the ListBox and only set the TargetType and not the x:Key, it will be applied automatically.
You can even nest this automatic application using Resources, e.g.:
<ListBox>
<ListBox.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Resources>
<Style TargetType="{x:Type Image}">
<Setter Property="Width" Value="100"/>
</Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="Blue"/>
</Style>
</Style.Resources>
</Style>
</ListBox.Resources>
<!-- Items here -->
</ListBox>

Related

UWP-CPP/Winrt Set Corner radius of the ListViewItem when hovered/selected

I am planning to show a list of objects using ListView. According to the design the rectangle around the ListViewItem should be rounded at the corners. Have tried multiple ways to achieve the same but couldn't find a solution.
<ListView
x:Name="ObjectList"
ItemsSource="{x:Bind ObjectViewModel.Objects}"
SelectionChanged="ListViewButtonClick"
MaxWidth ="{StaticResource ColumnMaximumWidth}"
VerticalAlignment = "Center"
HorizontalContentAlignment = "Stretch"
ScrollViewer.HorizontalScrollBarVisibility ="Disabled"
SelectionMode ="Single" />
<ListView.Resources>
<SolidColorBrush x:Key="ListViewItemBackgroundSelected" Color="Green" />
<SolidColorBrush x:Key="ListViewItemBackgroundSelectedPointerOver" Color="Green" />
</ListView.Resources>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Margin" Value="0,0,0,30" />
</Style>
</ListView.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="local:ObjectModel">
<Border
BorderBrush="Red"
BorderThickness="3"
CornerRadius="5">
<Grid MinHeight="66" CornerRadius="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<FontIcon
FontSize="17"
Glyph=""
Style="{StaticResource FontIconStyle1}" />
<TextBlock
Grid.Column="1"
Style="{StaticResource AddBluetoothLabelTextStyle}"
Text="{x:Bind ObjectName, Mode=OneWay}" />
</Grid>
</Border>
</ItemsControl.ItemTemplate>
</ListView>
As shown in the picture the corners of the selected/hovered items is not rounded. Can you please help how this can be achieved. TIA
You need to change the VisualState to set CornerRadius of ListViewItem in style of ListViewItem.
Please check the following steps:
Open generic.xaml file, find a Style whose TargetType is ListViewItem and Key is ListViewItemRevealStyle. Copy the style into your Page.Resources.
Delete the x:Key property of the style so that the style could be used in all ListViewItem in the current Page.
Find a VisualState whose name is Selected, add the following code:
<VisualState x:Name="Selected">
<VisualState.Setters>
<Setter Target="Root.CornerRadius" Value="10" />
</VisualState.Setters>
</VisualState>
Find VisualStates whose names are PointerOver, PointerOverSelected, PointerOverPressed, PointerOverPressed, add the following code seperately:
<Setter Target="Root.CornerRadius" Value="10" /> <!--Add this code-->
Delete the ListView.ItemContainerStyle statement, which conflicts with the ListViewItem’s style.
Note, it is better if you could follow the above steps first to set corner radius in the style of ListViewItem then add other style or settings later, which could ensure settings in the style of ListViewItem work.

Style resource inheriting from parent

I've got two stack panels nested within another stackpanel, the nested stack panels both have images in which need to be the same size, so I've used a style resorce. But this means duplicating the style resources in each stack panel. As shown;
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horiztonal">
<StackPanel.Resources>
<Style TargetType="Image">
<Setter Property="Width" Value="20"/>
</Style>
</StackPanel.Resources>
<Image />
<Image />
<Image />
<Image />
</StackPanel>
<StackPanel Orientation="Horiztonal">
<StackPanel.Resources>
<Style TargetType="Image">
<Setter Property="Width" Value="20"/>
</Style>
</StackPanel.Resources>
<Image />
<Image />
<Image />
<Image />
</StackPanel>
</StackPanel>
Is there a way to set this style on my surrounding stackpanel and have the children inherit that style, or would I be looking at making a style template (as shown; https://learn.microsoft.com/en-us/dotnet/framework/wpf/controls/styling-and-templating) and applying it individually to my images?
I do not recommend inheriting style using "previous style" as the base. Instead, I would define the style explicitly as the base style as a static resource, and then apply the style to any control that needs that style (or inherit the style).
For ex:
In the User Control level, let's define the base style.
<UserControl>
<UserControl.Resources>
<!--Define StackPanel Style with a key as the base-->
<Style x:Key="ImageStyle" TargetType="{x:Type Image}">
<Setter .... />
</Style>
<!-- To apply the style above, you need to explicitly set the style using Style="{StaticResource ImageStyle}"-->
</UserControl.Resources>
</UserControl>
In the body, we can apply the style to specific Control, but in our case we want to apply to all Images inside the OuterStackPanel, therefore:
<StackPanel x:Name="OuterStackPanel">
<StackPanel.Resources>
<!-- Without specifying the key, this will apply the style to all Images inside this StackPanel including NestedStackPanels -->
<!-- Also, with BasedOn, this will inherit the style from ImageStyle defined above -->
<Style TargetType="{x:Type Image}" BasedOn="{StaticResource ImageStyle}">
<Setter .../> <!-- In Case if you want to add another setter, for ex: Width=20. Or don't add any other Setter to have the original style-->
</Style>
</StackPanel.Resources>
<StackPanel x:Name="NestedStackPanel1">
<Image />
<Image />
<Image />
<Image />
</StackPanel>
<StackPanel x:Name="NestedStackPanel2">
<Image />
<Image />
<Image />
<Image />
</StackPanel>
</StackPanel>
If you need to have different style for each nestedStackPanel, you can move the styling inside the nestedStackPanel, instead.

How Can I Reuse an Icon in Resources in UWP? In WPF, I'd use x:Shared=false

I am trying to create a button Style that I can use for a "Lookup" button throughout my UWP app. However, the icon only appears on the first button on the screen. I tried this solution using templates, but it is not working for me. Thanks for the help.
Code:
<Page.Resources>
<ControlTemplate x:Key="FindSymbolTemplate">
<SymbolIcon Symbol="Find" Foreground="White" />
</ControlTemplate>
<Style TargetType="Button" x:Key="LookupButton">
<Setter Property="Content">
<Setter.Value>
<ContentControl Template="{StaticResource FindSymbolTemplate}" />
</Setter.Value>
</Setter>
</Style>
</Page.Resources>
....
<Button x:Name="tourNumLookup"
Style="{StaticResource LookupButton}"
Grid.Column="1"
Margin="10,0"
VerticalAlignment="Center" />
....
<Button x:Name="customerIdLookup"
Style="{StaticResource LookupButton}"
VerticalAlignment="Center"
Grid.Column="1"
Grid.Row="1"
Margin="10,0" />
The two buttons in the UI. Only the first has the SymbolIcon content.
#Romasz's solution absolutely works, but what if you want a lightly different Foreground on the SymbolIcon inside another Button?
Here's a potentially more flexible way that I normally go with.
First let's create a base Style that holds some default values for all the icons.
<Style x:Key="Style-Icon-Base"
TargetType="ContentControl">
<!-- If you don't specify the Foreground, it will use its ancestor's -->
<!--<Setter Property="Foreground"
Value="White" />-->
<Setter Property="HorizontalContentAlignment"
Value="Center" />
<Setter Property="VerticalContentAlignment"
Value="Center" />
<Setter Property="Width"
Value="20" />
<Setter Property="Height"
Value="20" />
<Setter Property="Padding"
Value="0" />
</Style>
Then we create a new icon Style which inherits from the one above. Note within the ControlTemplate I have used TemplateBinding to make property values dynamic. TemplateBinding isn't available inside a DataTemplate.
<Style x:Key="Style-Icon-Find"
BasedOn="{StaticResource Style-Icon-Base}"
TargetType="ContentControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<!--
'cause you cannot change the size of the SymbolIcon, we insert a Viewbox here,
otherwise you don't need it.
-->
<Viewbox Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
<SymbolIcon Symbol="Find"
Foreground="{TemplateBinding Foreground}" />
</Viewbox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This way you have created a highly reusable icon Style, to use it, have a look at the following Buttons:
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center">
<Button Margin="4"
Padding="8"
BorderBrush="LightBlue">
<ContentControl Width="36"
Height="36"
Foreground="DarkCyan"
Style="{StaticResource Style-Icon-Find}" />
</Button>
<!-- Note how I defined the Foreground at the Button level and it flows down to the icon -->
<Button Foreground="DarkGoldenrod"
Margin="4">
<StackPanel Orientation="Horizontal">
<ContentControl Style="{StaticResource Style-Icon-Find}"
Width="16"
Height="16" />
<TextBlock Text="Search"
VerticalAlignment="Center"
Margin="8,0,0,0" />
</StackPanel>
</Button>
<Button Margin="4"
Padding="4">
<ContentControl Style="{StaticResource Style-Icon-Find}" />
</Button>
</StackPanel>
And they look like:
Generally UI elements can be used once (or saying different - have only one parent) - this is probably why it only works for the first button in your case. One solution may be to define DataTemplate and use it as ContentTemplate, so each button creates its own icon:
<Page.Resources>
<DataTemplate x:Key="FindTemplate">
<SymbolIcon Symbol="Find" Foreground="White" />
</DataTemplate>
</Page.Resources>
...
<Button x:Name="tourNumLookup" ContentTemplate="{StaticResource FindTemplate}"
Grid.Column="1" Margin="10,0" VerticalAlignment="Center" />
<Button x:Name="customerIdLookup" ContentTemplate="{StaticResource FindTemplate}"
VerticalAlignment="Center" Grid.Column="1" Grid.Row="1" Margin="10,0" />
You don't need to create ControlTemplate to reuse the icon. You can simply put this SymbolIcon to the resource dictionary and use as StaticResource for the buttons' Content.
<Page.Resources>
<SymbolIcon x:Key="FindSymbol" Symbol="Find" Foreground="White" />
</Page.Resources>
<Button x:Name="tourNumLookup"
Content="{StaticResource FindSymbol}"
Grid.Column="1"
Margin="10,0"
VerticalAlignment="Center" />
<Button x:Name="customerIdLookup"
Content="{StaticResource FindSymbol}"
VerticalAlignment="Center"
Grid.Column="1"
Grid.Row="1"
Margin="10,0" />
UPDATE
BTW this is possibly a bug in the UWP platform, because I tried the following code and only the first Button rendered the icon at desing time and none of the at runtime.
<Page.Resources>
<SymbolIcon x:Key="FindSymbol" Symbol="Find" Foreground="White" />
<Style TargetType="Button" x:Key="LookupButton">
<Setter Property="Content" Value="{StaticResource FindSymbol}"/>
</Style>
</Page.Resources>
<StackPanel>
<Button x:Name="tourNumLookup"
Style="{StaticResource LookupButton}"
Margin="10,0"
VerticalAlignment="Center" />
<Button x:Name="customerIdLookup"
Style="{StaticResource LookupButton}"
VerticalAlignment="Center"
Margin="10,0" />
</StackPanel>
I tried to assign the Setter's Value directly but I got the same result. And also tried with FontIcon.

Unable to Bind ListView.SelectedItems.Count to Button.IsEnabled

I have a Button that I want to bind to the listview's selectedItem count. I cannot find where my error is. The button state is always enabled regardless of testListView.SelectedItems.Count.
Do I need a converter of some sort? If the Count is zero, it should implicitly convert that to a false no ?
<ListView x:Name="testListView" SelectionMode="Multiple" BorderThickness="1">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button x:Name="Button" Content="TestButton" IsEnabled="False" IsEnabled="{Binding ElementName=testListView, Path=SelectedItems.Count}"/>
Since the SelectedItems collection's Count property is of type int, and the IsEnabled property expects a bool input, and no implicit conversion of int to bool exists in C#, you'll need a converter or a data trigger.
A simple IValueConverter should do the trick, just use something like
return ((int)value) > 0;
as content of the Convert function!
Update using a DataTrigger via a Style; something like this should work:
<Button x:Name="Button" Content="TestButton">
<Button.Style>
<Style TargetType="Button">
<Setter Property="IsEnabled" Value="true" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=testListView, Path=SelectedItems.Count}" Value="0">
<Setter Property="IsEnabled" Value="false" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>

Fieldset in Winrt/XAML

I need to create something in WinRT/XAML similar to an HTML fielset. http://jsfiddle.net/Sf2Vy/
Basically, I have a border and there is some text on top of the border. Where the text covers the border, I need the border to not show under the text. The background behind the border isn't a solid color so I can't just set the background color of the text. The text length is variable also.
Is there an easy way to do this?
Yeah, so, the answer is no. There is no FieldSet.
Having said that, I think you could work out a similar effect simple enough. The code below shows you a solution that could easily be wrapped in a custom user control called fieldset.
<Grid Width="500" VerticalAlignment="Center">
<!-- top fieldset thing -->
<Grid VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="35" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.Resources>
<Style TargetType="Border">
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="BorderThickness" Value="0,5,0,0" />
<Setter Property="BorderBrush" Value="white" />
<Setter Property="Margin" Value="0,-2,0,0" />
</Style>
<Style TargetType="TextBlock">
<Setter Property="Margin" Value="10,-15,10,0" />
<Setter Property="FontSize" Value="30" />
</Style>
</Grid.Resources>
<Border Grid.Column="0" />
<TextBlock Grid.Column="1" Text="User Info" />
<Border Grid.Column="2" />
</Grid>
<!-- regular form fields -->
<Border BorderBrush="White" BorderThickness="5,0,5,5">
<StackPanel Margin="20">
<TextBox Header="Salutation" />
<TextBox Header="First Name" />
<TextBox Header="Middle Name" />
<TextBox Header="Last Name" />
<Button Margin="0,5,-3,0" HorizontalAlignment="Right">Save Data</Button>
</StackPanel>
</Border>
</Grid>
It looks something like this:
It's not 100% perfect - or, maybe... it is.
Best of luck!