Linking ThemeDictionaries in Library Project - xaml

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>

Related

How can I define a theme in a UWP Library?

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.

How to customize Acrylic brush

I want to paint Stack Panel surface using Acrylic brush.
<StackPanel Background="{ThemeResource SystemControlAcrylicElementBrush}"></StackPanel>
It works for me but there is a problem when I want to change Tint color and opacity. There is a following code to change it:
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Default">
<AcrylicBrush x:Key="MyAcrylicBrush"
BackgroundSource="HostBackdrop"
TintColor="#FFFF0000"
TintOpacity="0.8"
FallbackColor="#FF7F0000"/>
</ResourceDictionary>
I don't know where should I place it and rename brush for this?
<StackPanel Background="{ThemeResource **MyAcrylicBrush**}"></StackPanel>
Thanks for help.
P.S. You need Windows Insider SDK and system build 16190 or higher
You can create a ResourceDictionary, for example called "ThemeDictionary.xaml" and put the code you have for your AcrylicBrush in there.
Then in your App.xaml you can reference your ResourceDictionary like so:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ThemesDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Method 1:
Add ResourceDictionary.ThemeDictionaries in Application.Resources
In App.xaml
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Default">
<AcrylicBrush x:Key="MyAcrylicBrush" BackgroundSource="HostBackdrop" TintColor="#FFFF0000" TintOpacity="0.8" FallbackColor="#FF7F0000"/>
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<SolidColorBrush x:Key="MyAcrylicBrush" Color="{ThemeResource SystemColorWindowColor}"/>
</ResourceDictionary>
<ResourceDictionary x:Key="Light">
<AcrylicBrush x:Key="MyAcrylicBrush" BackgroundSource="HostBackdrop" TintColor="#FFFF0000" TintOpacity="0.8" FallbackColor="#FFFF7F7F"/>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
</Application.Resources>
Method 2:
As #jsmyth886 answered
Add a separate ResourceDictionary file and place your ResourceDictionary.ThemeDictionaries code
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Default">
<AcrylicBrush x:Key="MyAcrylicBrush" BackgroundSource="HostBackdrop" TintColor="#FFFF0000" TintOpacity="0.8" FallbackColor="#FF7F0000"/>
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<SolidColorBrush x:Key="MyAcrylicBrush" Color="{ThemeResource SystemColorWindowColor}"/>
</ResourceDictionary>
<ResourceDictionary x:Key="Light">
<AcrylicBrush x:Key="MyAcrylicBrush" BackgroundSource="HostBackdrop" TintColor="#FFFF0000" TintOpacity="0.8" FallbackColor="#FFFF7F7F"/>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
You MergedDictionaries in App.xaml to Merged your ResourceDictionary file
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Dictionary1.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
For more Info: ResourceDictionary and XAML resource references, XAML for Windows 10 Controls - Styling

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>

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>