Add a mouseover and pressed/clicked effect on element in UWP app - c#

I'm currently working on an app to show all parking spaces in Kortrijk (a city in Belgium). This is how it looks at the moment:
Design
My question is: how can I for example change the color of the element on mouseover or on click. I want to accomplish this in the XAML and this is the code that I have now.
Code
MainPage.xaml
<Page
x:Class="ParkingSpots.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ParkingSpots"
xmlns:model="using:ParkingSpots.model"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:Maps="using:Windows.UI.Xaml.Controls.Maps"
mc:Ignorable="d">
<Page.Resources>
<model:ParkingSpot x:Key="spots"/>
</Page.Resources>
<Grid Style="{StaticResource mainGrid}">
<Grid.RowDefinitions>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Parking spots in Kortrijk"/>
<ListView ItemsSource="{Binding Source={StaticResource spots}, Path=ParkingSpots}" ItemTemplate="{StaticResource ParkingSpotTemplate}" ItemsPanel="{StaticResource ParkingSpotsTemplate}"/>
</Grid>
style.xaml (external xaml file)
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ParkingSpots.style"
xmlns:conv="using:ParkingSpots.converter">
<conv:StreetConverter x:Key="StreetConv" />
<Color x:Key="Color1">#FFB3B6F2</Color>
<Color x:Key="Color2">#FF5A58D9</Color>
<Color x:Key="Color3">#FFF2F2F2</Color>
<SolidColorBrush x:Key="Color1Brush" Color="{StaticResource Color1}" />
<SolidColorBrush x:Key="Color2Brush" Color="{StaticResource Color2}" />
<SolidColorBrush x:Key="Color3Brush" Color="{StaticResource Color3}" />
<Style x:Name="mainGrid" TargetType="Grid">
<Setter Property="Background" Value="{StaticResource Color1Brush}"/>
</Style>
<DataTemplate x:Key="ParkingSpotTemplate">
<ListViewItem>
<ListViewItem.Resources>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="{StaticResource Color3Brush}" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Margin" Value="8,0,0,0" />
</Style>
</ListViewItem.Resources>
<TextBlock x:Name="ParkingSpotInfo" Grid.Row="0" Grid.Column="0" Text="{Binding Street, Converter={StaticResource StreetConv}}"/>
</ListViewItem>
</DataTemplate>
<ItemsPanelTemplate x:Key="ParkingSpotsTemplate">
<VariableSizedWrapGrid x:Name="wrapGrid"></VariableSizedWrapGrid>
</ItemsPanelTemplate>
I tried something with style.triggers but this is only possible in WPF apps and not in UWP apps. I've also read a lot of things about visualstates but I don't know how to use it and if this is the best way to do such effects.
Thanks in advance

You should probably be using a ListView to display this data instead of an ItemsControl (unless you have a good reason for doing so). ListView extends from ItemsControl and adds to it lots of useful features, such as:
Single/multiple item selection.
ItemClick event.
Each item container is a ListViewItem control which has its own features like visual states and a checkbox, and the presentation of the ListViewItem is managed by a ListViewItemPresenter which can deliver these features in an optimized manner.
Built-in ScrollViewer.
Data and UI virtualization. UI virtualization is a big advantage when you have 100s of items.
Accessible. Supports tab-focusing.
Probably more...
ItemsControl isn't typically used for situations where you want to interact with the items (by click/tap, for example).
ListView by default has its own style which can be easily overridden to match what you have already.
If you only want to style the ListViewItem background/foreground for each visual state, then you can override these styles:
<ListView>
<ListView.Resources>
<!--
These resources are applied to this ListView only. Put in a
higher scope (page or app) depending on what you want it to affect.
-->
<SolidColorBrush x:Key="ListViewItemBackgroundPointerOver" Color="Red"/>
<SolidColorBrush x:Key="ListViewItemForegroundPointerOver" Color="Violet"/>
<SolidColorBrush x:Key="ListViewItemBackgroundSelected" Color="Yellow"/>
<SolidColorBrush x:Key="ListViewItemForegroundSelected" Color="LimeGreen"/>
<SolidColorBrush x:Key="ListViewItemBackgroundSelectedPointerOver" Color="Blue"/>
<SolidColorBrush x:Key="ListViewItemBackgroundPressed" Color="Cyan"/>
<SolidColorBrush x:Key="ListViewItemBackgroundSelectedPressed" Color="Orange"/>
</ListView.Resources>
</ListView>

Related

How can I avoid overriding a window-wide style in WPF?

I'm using the MaterialDesign nuget package for my WPF application.
According to the tutorial, by applying window-wide properties, every element will inherit the MaterialDesign style.
However, if I apply a custom style to an element, that element loses its MaterialDesign style.
I can get around this by applying inline styles, but that is very repetitive and error prone.
I think the picture shows it better:
And here is my xaml:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TestApp"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" x:Class="TestApp.MainWindow"
mc:Ignorable="d"
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextElement.FontWeight="Regular"
TextElement.FontSize="13"
TextOptions.TextFormattingMode="Ideal"
TextOptions.TextRenderingMode="Auto"
Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{DynamicResource MaterialDesignFont}"
Title="MainWindow" Height="450" Width="600">
<!--All of the above is meant to apply Material Design to the entire Window-->
<StackPanel>
<StackPanel.Resources>
<!--This style overrides the Material Design style entirely,
instead of just Margin and Horizontal Alignment-->
<Style x:Key="SpacedButton" TargetType="Button">
<Setter Property="Margin" Value="0 10"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
</Style>
</StackPanel.Resources>
<!--Material Design only works by applying properties directly to elements-->
<Button Content="Button #1" HorizontalAlignment="Center" Margin="0 10"/>
<Button Content="Button #2" Style="{DynamicResource SpacedButton}"/>
<Button Content="Button #3" Style="{DynamicResource SpacedButton}"/>
<Button Content="Button #4" HorizontalAlignment="Center" Margin="0 10"/>
</StackPanel>
</Window>
As you can see, only elements with inline properties keep the MaterialDesign style, but by applying a custom style, the MaterialDesign style is lost.
How can I make sure that MaterialDesign is applied to every element, while still being able to override specific properties with custom styles?
Sorry if some of the terminology is wrong, I'm pretty new to WPF.
Use Style.BasedOn to inherit properties from whichever other style is in scope:
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
...etc....
Or a specific one:
<Style x:Key="ThisStyleKey" TargetType="{x:Type Button}" BasedOn="{StaticResource OtherStyleKey}">
...etc....

How to add specific Style to Framework Elements contained on a User Control, with XAML?

I create a basic UserControl, called InputTag; it has two FrameworkElements a TextBlock and a Textbox.
Using the dependency properties I control the input for this control. The name of dependency properties are "Field" for the textblock, and "Value" for the Textbox.
The user control is compiled into a DLL (Class Library) and then loaded on a Windows Application.
Here is the XAML code for the UserControl:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="FieldName" Text="Tag"/>
<TextBox x:Name="FieldValue" Grid.Column="0" Text="0"/>
</Grid>
And in the windows app MainWindow.xaml I insert the control like this
<t:InputTag Field="Name" Value="" />
I want to add different styles to the Textblock and the TextBox using a Resource Dictionary, it should work like this
<t:InputTag Field="Name" Value="" Style="{StaticResource InputTagStyle}"/>
For this example lets say we had two different font sizes. My Resource dictionary looks like this:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:t="clr-namespace:Terra.Controls;assembly=Terra">
<Style x:Key="InputTagStyle" TargetType="{x:Type t:InputTag}">
<Style.Setters>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<TextBlock Style="{StaticResource InputTagStyle}"/>
<TextBox Style="{StaticResource InputTextStyle}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
<Style x:Key="InputTagStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="15"/>
</Style>
<Style x:Key="InputTextStyle" TargetType="TextBox">
<Setter Property="FontSize" Value="12"/>
</Style>
</ResourceDictionary>
The problem is that I don't know how to access a subkey of my control, and it seems that if I use ControlTemplate is like creating new content to my control.
You need to refer to import the resources into your xaml as a pack URI format thus to import your styling keys in the section like this:
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Terra;component/Styles/ButtonStyles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>

How to override the PhoneAccentBrush in WindowsPhone?

Basically PhoneAccentBrush comes with the SelectedTheme accent color from Phone. But i need always BlueAccentBrush for specific xaml file in the WindowsPhone application.
Actually my requirement is, When the ListPicker is in FullMode.. The SelectedItem color in the Popup depends upon the PhoneAccentBrush... If i set the Phone theme as Red.. then SelectedItem color in the Popup will be red.. But i dont like this.. I want always BlueAccentBrush for the SelectedItem in the Popup..
So can anyone help me to override the PhoneAccentBrush in the xaml file..
Add ListPicker as below,
<StackPanel x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0" >
<toolkit:ListPicker ListPickerMode="Full">
<toolkit:ListPickerItem Content="Item1"/>
<toolkit:ListPickerItem Content="Item1"/>
<toolkit:ListPickerItem Content="Item2"/>
<toolkit:ListPickerItem Content="Item3"/>
<toolkit:ListPickerItem Content="Item4"/>
</toolkit:ListPicker>
</StackPanel>
To override the ListPicker Selected Item Color
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:System="clr-namespace:System;assembly=mscorlib">
<Color x:Key="PhoneAccentColor">Blue</Color>
<SolidColorBrush x:Key="PhoneAccentBrush" Color="{StaticResource PhoneAccentColor}"/>
<Style x:Key="PhoneTextAccentStyle" TargetType="TextBlock" BasedOn="{StaticResource PhoneTextBlockBase}">
<Setter Property="FontFamily" Value="{StaticResource PhoneFontFamilySemiBold}"/>
<Setter Property="Foreground" Value="{StaticResource PhoneAccentBrush}"/>
</Style>
</ResourceDictionary>
For more Details refer the below sample: http://www.windowsphonegeek.com/upload/articles/MangoCustomApplicationTheme%20_1_2_3.zip
You can't override PhoneAccentBrush. It's a "system" resource. But you can change the way the ListPicker behaves. See http://windowsphonegeek.com/articles/customizing-listpicker-for-wp7-part1 for a series of articles that show how.

I need help implementing a style into my radTreeView

I want to take the highlight background off of the radtreeview. I created a style to do this, but I keep getting errors and exceptions such as "Items collection must be empty." If I comment out the style the application works fine, so I know that it is the cause of the problem. I am fairly new to WPF, and I am sure I just don't understand how to use styles yet.
Thanks for your help. Here is the code.
<Grid x:Name="LayoutRoot" Background="Salmon">
<telerik:RadTreeView x:Name="radTreeView" Margin="8" ItemsSource="{Binding Errors}" Background="Salmon" Style="{StaticResource treeStyle}">
<Style TargetType="{x:Type telerik:RadTreeViewItem}" x:Name="treeStyle">
<Setter Property="Focusable" Value="False"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" Value="{x:Null}"/>
<Setter Property="BorderBrush" Value="{x:Null}"/>
</Trigger>
</Style.Triggers>
</Style>
<telerik:RadTreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding SubItems}" >
<Grid Background="Salmon">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Text="{Binding Description}" IsHitTestVisible="False" />
<ListBox Grid.Row="1" ItemsSource="{Binding Messages}" Margin="20,0,0,0" BorderBrush="#00000000" BorderThickness="0" Background="Salmon" IsHitTestVisible="False" >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Message}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</HierarchicalDataTemplate>
</telerik:RadTreeView.ItemTemplate>
</telerik:RadTreeView>
</Grid>
</UserControl>
If you know that this is not going to work, I was also trying to get rid of the highlight with the style code:
<Style TargetType="TreeViewItem">
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="#FFF"/>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="#000"/>
</Style.Resources>
</Style>
You get exceptions because your style tag is actually an item in the tree, and you have ItemsSource set.
Surround the style with <telerik:RadTreeView.ItemContainerStyle> tag.
This should solve the exception but it will not give you the result that you expect since the control template of the tree view item is actually showing another border that is not affected by the Background property. You will need to change the control template.
Telerik change the styles between releases, so giving you a template of a wrong version will probably won't help you.
But, you can go to the installation folder for Telerik and look for a folder called "Themes". There you'll find a solution with all the themes for telerik.
Choose the one that you use.
Find the resource dictionary for the tree view and copy the style and template for the item to your project.
Change xmlns definitions, make sure you have all the brushes and resources that the style depends upon.
Run to see that the style is ok.
In the template, find the VisualState with x:Name="MouseOver" and delete the storyboard inside it.

What WPF control or approach for this requirement?

Just being new to WPF I"m not sure what control or approach would be best for this requirement, for a WPF application.
I want to present a summary table of information, but the user should be able to decide to view the information based on either: "All Time", Month, Week or Day.
I'd like to visually have the selection of the option appear at the top of this section and have it appear as a TabControl
I'm not sure however whether TabControl is the best choice re repeating the table for each Tab Item
So overall functionally what would work is just radio buttons across the top, however what I want visually is a TabControl look
What would be the best way to achieve the TabControl look but with a programming approach for which I don't have to repeat things in each Tab Item?
For example, would I use a TabControl and then a WPF template to do the equivalent of an include in each Tab Item but with a different input parameter? (haven't used WPF templates before)
Thanks
Since you want the behavior of a group of RadioButtons and you want the visual appearance of a TabItem, you should use RadioButton controls and style them such that they look like TabItem controls. Here is a very simple example:
<Window x:Class="TabTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<Style TargetType="{x:Type RadioButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RadioButton}">
<Border x:Name="tabBorder" BorderThickness="1" BorderBrush="Black"
Margin="0,0,-4,0"
CornerRadius="2,12,0,0"
Background="White"
SnapsToDevicePixels="True">
<ContentPresenter
Margin="12,2,12,2"
VerticalAlignment="Center"
HorizontalAlignment="Left"
RecognizesAccessKey="True"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Panel.ZIndex" Value="100" />
<Setter TargetName="tabBorder" Property="Background" Value="LightBlue" />
<Setter TargetName="tabBorder" Property="BorderThickness" Value="1,1,1,0" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid Margin="4">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,0,0,-1" Panel.ZIndex="1">
<RadioButton>All Time</RadioButton>
<RadioButton IsChecked="True">Month</RadioButton>
<RadioButton>Week</RadioButton>
<RadioButton>Day</RadioButton>
</StackPanel>
<Border Grid.Row="1" Background="LightBlue"
BorderThickness="1" BorderBrush="Black"
SnapsToDevicePixels="True">
<Button Margin="10" Grid.Row="1">This is a test</Button>
</Border>
</Grid>
</Window>
In this example, the Button is the place where you would put your summary table.
Greg, I suppose, grouping grid would be the most ideal control of your requirement. Either you can customize the datagrid as explained in the following article. But this would take more time to get things right.
http://blog.smoura.com/wpf-toolkit-datagrid-part-iv-templatecolumns-and-row-grouping/
or else you could make use of commercial WPF Grid grouping control which would match you requirement.
What would be the best way to achieve the TabControl look but with a programming approach for which I don't have to repeat things in each Tab Item?
Use a TabControl. Have each TabItem contain a CollectionViewSource based on the same underlying collection of data, but with a different filter. Use a DataTemplate to present the CollectionViewSource.
Filtering requires some kind of code-behind, but here's a XAML-only demo that does sorting:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase">
<Page.Resources>
<XmlDataProvider x:Key="Data">
<x:XData>
<Data xmlns="">
<Item Date="2010-01-01" Value="January"/>
<Item Date="2010-02-01" Value="February"/>
<Item Date="2010-03-01" Value="March"/>
<Item Date="2010-04-01" Value="April"/>
<Item Date="2010-05-01" Value="May"/>
<Item Date="2010-06-01" Value="June"/>
<Item Date="2010-07-01" Value="July"/>
<Item Date="2010-08-01" Value="August"/>
<Item Date="2010-09-01" Value="September"/>
</Data>
</x:XData>
</XmlDataProvider>
<CollectionViewSource x:Key="ByDate" Source="{Binding Source={StaticResource Data}, XPath=Data/Item}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="#Date"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
<CollectionViewSource x:Key="ByValue" Source="{Binding Source={StaticResource Data}, XPath=Data/Item}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="#Value"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
<DataTemplate DataType="{x:Type CollectionViewSource}">
<Border Margin="5" BorderBrush="DodgerBlue" BorderThickness="1" CornerRadius="4">
<DockPanel Margin="5">
<Label DockPanel.Dock="Top">This is here to show how you can make the layout of your TabItems complex without repeating yourself.</Label>
<ListBox DockPanel.Dock="Top" x:Name="Items" ItemsSource="{Binding}" DisplayMemberPath="#Value" SelectedValuePath="#Value"/>
<DockPanel>
<Label>Selected item: </Label>
<Label Content="{Binding ElementName=Items, Path=SelectedValue}"/>
</DockPanel>
</DockPanel>
</Border>
</DataTemplate>
</Page.Resources>
<Grid>
<TabControl>
<TabItem Header="By date" Content="{StaticResource ByDate}"/>
<TabItem Header="By value" Content="{StaticResource ByValue}"/>
</TabControl>
</Grid>
</Page>

Categories