How can I define a theme in a UWP Library? - xaml

I'm creating a UWP library that contains custom controls and I want to define a dark and light theme for my controls. I understand that we can add a theme resource dictionary to the App.xaml. We can specify a dark/light theme there and set the requested theme property. But since I am making a library, I don't have an App.xaml in my project. Is it possbile for me to define a theme within the library project? How?

You can create a resource dictionary file in Microsoft Visual Studio by using the Add > New Item… > Resource Dictionary option from the Project menu. Then we can define the ThemeDictionaries in the ResourceDictionary file.
For example:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ClassLibrary1">
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Light">
<SolidColorBrush x:Key="CustomColor" Color="Orange" />
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<SolidColorBrush x:Key="CustomColor" Color="Blue" />
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<SolidColorBrush x:Key="CustomColor" Color="Green" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
To use that dictionary, we can merge it with control’s dictionary:
<UserControl
x:Class="ClassLibrary1.MyUserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ClassLibrary1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dictionary1.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Rectangle Fill="{ThemeResource CustomColor}" Width="500" Height="500"></Rectangle>
</Grid>
</UserControl>
If you want to specify a dark/light theme, you can set RequestedTheme in the Control.

Related

Use Dictionary from another folder in XAML UWP

this is the content of my dictionary [Dictionaries/myDictionary.xaml]:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:myApp/Dictionaries"
xmlns:media="using:Windows.UI.Xaml.Media">
<ResourceDictionary x:Key="Default">
<AcrylicBrush x:Key="myAcrylicBrush"
BackgroundSource="HostBackdrop"
TintColor="#202020"
TintOpacity="0.8"
FallbackColor="#202020"/>
</ResourceDictionary>
</ResourceDictionary>
And here is where I need to use it [Pages/myPage]:
<Page
x:Class="myApp.Pages.myPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:myApp.Pages"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
xmlns:animations="using:Microsoft.Toolkit.Uwp.UI.Animations"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!-- Here it gives me error -->
<ResourceDictionary Source="pack://application:,,,/ReferencedAssembly;component/Dictionaries/myDictionary.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style x:Key="myStyle" TargetType="Grid">
<Setter Property="Background" Value="{StaticResource myAcrylicBrush}"/>
</Style>
</ResourceDictionary>
</Page.Resources>
<Grid x:Name="gridPrincipale" Style="{StaticResource myStyle}">
</Grid>
</Page>
I've tried
Source="pack://application:,,,/ReferencedAssembly;component/Dictionaries/myDictionary.xaml"
but it doesn't work…
Both folders "Dictionaries" and "Pages" are in the Project's folder.
For UWP you'll want to use the ms-appx location for the Souce.
Example:
<ResourceDictionary Source="ms-appx:///Company.Themes/Dictionaries/myDictionary.xaml" />
Where Company.Themes is the project name, and Dictionaries/myDictionary.xaml is the location of the resource file from the root of the project

x:Bind in resource dictionary doesn't work

I'm struggling to get a grip of the compiled databinding concept. I have one view (MainPage) that contains a ListBox and one data template (ItemTemplate) used for that ListBox. The MainPage has a MainPageViewModel that contains an ObservableCollection of ItemViewModels. The ItemViewModel contains only one property Name.
MainPage:
<Page x:Class="TestApp.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TestApp">
<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ItemDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ListBox ItemsSource="{x:Bind ViewModel.Items}"
ItemTemplate="{StaticResource ItemTemplate}" />
</Grid>
</Page>
Resource dictionary containing datatemplate:
<ResourceDictionary
x:Class="TestApp.ItemDictionary"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TestApp">
<DataTemplate x:Key="ItemTemplate" x:DataType="local:ItemViewModel">
<TextBlock Text="{x:Bind Name}" />
</DataTemplate>
</ResourceDictionary>
This code compiles but when I run it the binding to the Name property fails, although the items get generated. If I use a classic binding everything works fine and if I place the data template directly in the resources for the MainPage it also works. What am I missing?
Correct:
<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<local:ItemDictionary />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Page.Resources>
Incorrect:
<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ItemDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Page.Resources>

Linking ThemeDictionaries in Library Project

I created 2 ResourceDictionary/theme files in Themes folder named Light.xaml and Dark.xaml.
Added SolidColorBrush with name BgColor in both files :
<SolidColorBrush x:Name="BgColor" Color="Silver" /> // in Light.xaml
<SolidColorBrush x:Name="BgColor" Color="WhiteSmoke" /> // in Dark.xaml
In Application type project, I can add below XAML code in App.xaml so I can reference this resource in my UserControl :
<Application>
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Dark" Source="Themes/Dark.xaml" />
<ResourceDictionary x:Key="Light" Source="Themes/Light.xaml"/>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
Since this is Library Project, there's no App.xaml on my project.
So how to link this ThemeDictionaries so I can use it in my UserControl in Library Project ?
So how to link this ThemeDictionaries so I can use it in my UserControl?
You can reference the resource dictionary in your App.xaml like below:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Dark" Source="ms-appx:///MyThemeLibrary/Themes/Dark.xaml"/>
<ResourceDictionary x:Key="Light" Source="ms-appx:///MyThemeLibrary/Themes/Light.xaml"/>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
</Application.Resources>
MyThemeLibrary is the reference name of your class library. After that you can use the theme that you defined in Dark.xaml and Light.xaml like below:
<UserControl
...
d:DesignHeight="300"
d:DesignWidth="400">
<Grid Background="{ThemeResource BgColor}">
</Grid>
</UserControl>

ListView DataTemplate in separate folder

I'm trying to learn programming apps for Universal Windows Platform. I'm currently working with ListView and I define its layout in <DataTemplate>, but the code is a one mess. Is there a way to define <DataTemplate> in a separate folder? I searched the net but I wasn't able to find a solution. Could you please help me with that? Thanks.
I would always recommend creating a ResourceDictionary for this kind of thing. Here's an example setup:
Create a folder Resources > Add > New item > Resource Dictionary "Templates.xaml"
In your App.xaml add
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Templates.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
In Templates.xaml you can add any template you want, like so:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:thestory.Resources">
<DataTemplate x:Key="ListItemTemplate">
</DataTemplate>
You can now reference this template wherever you need it using {StaticResource ListItemTemplate}
Good Luck!
PS: I would actually also recommend doing the same for styles and other application wide resources like font sizes, brushes, backgrounds etc.
In datatemplate.xaml define datatemplate:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DataTemplate>
</DataTemplate>
</ResourceDictionary>
In UserControl refer to datatemplate:
<UserControl
x:Class="<assemblyName>.Themes.MyUserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:PerpetuumSoft.DataManager.UniApp.UI.Themes"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ms-appx:///<AssemblyName>/Themes/DataTemplate.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
</Grid>
</UserControl>

UWP, App.Xaml: Override default brushes

If I need to override a color in a brush, I would set it into App.xaml like this:
<Application.Resources>
...
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Light">
<SolidColorBrush x:Key="PivotHeaderForegroundUnselectedBrush" Color="#A7A9AC" />
<SolidColorBrush x:Key="PivotHeaderForegroundSelectedBrush" Color="Black" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
...
</Application.Resources>
The editor underlines <ResourceDictionary> saying: "Each dictionary entry must have an associated key".
How can solve this?
I solved the problem, thanks to #Alan Yao - MSFT.
Maybe you have more things there?, I had something else, written into the ResourceDictionary. By making ResourceDictionary parent of everything inside Application.Resources, I solved the problem.
The ResourceDictionary has to be placed inside application resources:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Light">
<SolidColorBrush x:Key="PivotHeaderForegroundUnselectedBrush" Color="#A7A9AC" />
<SolidColorBrush x:Key="PivotHeaderForegroundSelectedBrush" Color="Black" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
</Application.Resources>