Changing Xamarin Themes,styles per client approach - xamarin

what approach would you use if you have a mobile app build using xamarin and this app is like a vanilla app.
Each client should be able to apply their own style to labels etc.. theme
Basically all the views/pages are the same for all the clients but the style per page will change for each individual client.
If this wasn't a mobile app I would have plugins within a folder and depending on the client i would drop the relative plugin in the pluginFolder eg:pluginClientA etc.. and this would be discovered at runtime usin mef.
Any suggestions

Set you styles up as dynamicresources as seen here https://developer.xamarin.com/guides/xamarin-forms/user-interface/styles/dynamic/
I only have 2 themes so I have them specified in xaml
<ResourceDictionary>
<Color x:Key="Primary">#337ab7</Color>
<Color x:Key="Accent">#96d1ff</Color>
<Color x:Key="BackgroundColor">#C0C0C0</Color>
<Color x:Key="TextColor">White</Color>
<!-- Buttons -->
<Style x:Key="buttonStyle" TargetType="Button">
<Setter Property="BorderRadius" Value="4" />
<Setter Property="FontSize" Value="48" />
<Setter Property="FontAttributes" Value="Bold" ></Setter>
<Setter Property="HeightRequest">
<Setter.Value>
<OnPlatform x:TypeArguments="x:Double" iOS="80" Android="80" />
</Setter.Value>
</Setter>
<Setter Property="WidthRequest">
<Setter.Value>
<OnPlatform x:TypeArguments="x:Double" iOS="150" Android="150" />
</Setter.Value>
</Setter>
</Style>
<Style x:Key="btnPrimary" TargetType="Button" BasedOn="{StaticResource buttonStyle}">
<Setter Property="TextColor" Value="{DynamicResource TextColor}" />
<Setter Property="BackgroundColor" Value="{DynamicResource Primary}" />
</Style>
<!--Light Theme-->
<Color x:Key="Primary-Light">#2196F3</Color>
<Color x:Key="BackgroundColor-Light">#FAFAFA</Color>
<Color x:Key="TextColor-Light">White</Color>
<!--Dark Theme-->
<Color x:Key="Primary-Dark">#1976D2</Color>
<Color x:Key="BackgroundColor-Dark">#C0C0C0</Color>
<Color x:Key="TextColor-Dark">Black</Color>
</ResourceDictionary>
So in the theme change event you can change the assigned colours
Resources ["Primary"] = Resources ["Primary-Dark"];

Related

Why .NET-Maui Global Styles are not working?

I have declared global styles in .Net Maui and trying to access it from one of the pages but it's throwing exceptions
Microsoft.Maui.Controls.Xaml.XamlParseException: Position 10:37. Type converter failed: Exception has been thrown by the target of an invocation.
Microsoft.Maui.Controls.Xaml.XamlParseException: Position 8:34. StaticResource not found for key Primary.
App.xaml code
<?xml version = "1.0" encoding = "UTF-8" ?>
<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MyApp"
x:Class="MyApp.App">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Styles/Colors.xaml" />
<ResourceDictionary Source="Resources/Styles/Styles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
<Style x:Key="redLabelStyle"
TargetType="Label">
<Setter Property="TextColor"
Value="Red"/>
<Setter Property="FontSize"
Value="Small"/>
<Setter Property="FontAttributes"
Value="Bold"/>
</Style>
<Style TargetType="Label">
<Setter Property="TextColor"
Value="Green"/>
<Setter Property="FontSize"
Value="Small"/>
<Setter Property="FontAttributes"
Value="Bold"/>
</Style>
</Application.Resources>
MainPage.xaml code
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
NavigationPage.HasNavigationBar="False"
x:Class="MyApp.MainPage">
<VerticalStackLayout HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand">
<Label Style="{StaticResource redLabelStyle}"
Text="Global Style Red Label"/>
<Label Text="GLobal Style Green Label"/>
<Label Text="GLobal Style Green Label"/>
</VerticalStackLayout>
</ContentPage>
Note: This is the default app created by .Net Maui.
This is the wrong place i think </ResourceDictionary>
Try this :
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Styles/Colors.xaml" />
<ResourceDictionary Source="Resources/Styles/Styles.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style x:Key="redLabelStyle"
TargetType="Label">
<Setter Property="TextColor"
Value="Red"/>
<Setter Property="FontSize"
Value="Small"/>
<Setter Property="FontAttributes"
Value="Bold"/>
</Style>
<Style TargetType="Label">
<Setter Property="TextColor"
Value="Green"/>
<Setter Property="FontSize"
Value="Small"/>
<Setter Property="FontAttributes"
Value="Bold"/>
</Style>
</ResourceDictionary>
</Application.Resources>
Also give the second style a name. <Style TargetType="Label"> a name in x:Key=""
Like
x:Key="greenLabelStyle"
You can also add global styles to the Styles.xaml file referenced in your MergedDictionaries
Please note the location of file
<ResourceDictionary Source="Resources/Styles/Styles.xaml" />
You can copy your styles directly into there instead, allowing you to keep all of your global styles in one central place. This helps keep your App.xaml nice and tidy.

Standardize Xamarin Android Styles.xml and ResourceDictionary

I'm trying to avoid duplicate declaration of style definitions in both android styles.xml and resourcedictionary. For example,
In Android styles.xml, I've the following to change the default theme's primary color
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<style name="MyDefaultTheme">
<item name="colorPrimary">#color/colorPrimary</item>
</style>
<color name="colorPrimary">#0E80FF</color>
</resources>
And in DefaultResourceDictionary.xaml, I've the following so that my XF's controls uses the same color as defined in styles.xml:
<ResourceDictionary ...>
<Color x:Key="colorPrimary">#0E80FF</Color>
</ResourceDictionary>
On top of my head, I can think of doing some PreBuild actions to invoke XmlPoke to insert the value from ResourceDictionary into styles.xml.
Is there any less complicated ways of doing it?
Yes you can add styles in the App Class.
Example adding this in the App.xaml file
<Application.Resources>
<ResourceDictionary>
<Color x:Key="PrimaryColor">#512bdf</Color>
<Color x:Key="SecondaryColor">White</Color>
<Style TargetType="Label">
<Setter Property="TextColor" Value="{DynamicResource PrimaryColor}" />
<Setter Property="FontFamily" Value="OpenSansRegular" />
</Style>
<Style TargetType="Button">
<Setter Property="TextColor" Value="{DynamicResource SecondaryColor}" />
<Setter Property="FontFamily" Value="OpenSansRegular" />
<Setter Property="BackgroundColor" Value="{DynamicResource PrimaryColor}" />
<Setter Property="Padding" Value="14,10" />
</Style>
</ResourceDictionary>
</Application.Resources>

Xamarin: Style OnPlatform and DynamicResource

I have defined a style , but I'd like to set the Android and iOS values to a DynamicResource - What's the syntax?
<Style
TargetType="SearchBar" ApplyToDerivedTypes="true">
<Setter Property="BackgroundColor" Value="{OnPlatform Android='White', iOS='#4F8BBF'}"/>
</Style>
Per official documentation for different values for different targets
<!-- Colors -->
<Color x:Key="AppBackgroundColor">WhiteSmoke</Color>
<Color x:Key="iOSNavigationBarColor">WhiteSmoke</Color>
<Color x:Key="AndroidNavigationBarColor">#2196F3</Color>
<Color x:Key="iOSNavigationBarTextColor">Black</Color>
<Color x:Key="AndroidNavigationBarTextColor">White</Color>
<!-- Implicit styles -->
<Style TargetType="{x:Type NavigationPage}">
<Setter Property="BarBackgroundColor"
Value="{OnPlatform iOS={StaticResource iOSNavigationBarColor},
Android={StaticResource AndroidNavigationBarColor}}" />
<Setter Property="BarTextColor"
Value="{OnPlatform iOS={StaticResource iOSNavigationBarTextColor},
Android={StaticResource AndroidNavigationBarTextColor}}" />
</Style>
<Style TargetType="{x:Type ContentPage}" ApplyToDerivedTypes="True">
<Setter Property="BackgroundColor" Value="{StaticResource AppBackgroundColor}" />
</Style>
That's for setting different values
But if you are really looking for a literal dynamic resource, you'll have to set it in code behind constructor.
Here is the example
Resources ["searchBarStyle"] = Resources ["blueSearchBarStyle"];

Mvvmcross Xamarin Forms Navigation page style not working

I'm trying to style Navigation page on xamarin forms app with Mvvmcross.
before "adding" mmvcross I've defined style in App.xaml as follows.
<Style TargetType="NavigationPage">
<Setter Property="BarBackgroundColor" Value="Black" />
<Setter Property="BarTextColor" Value="White" />
</Style>
and it worked. I got background color and text color as i defined. Then we "moved" to Mvvmcross - we added all needed backend code, changed all pages from ContentPage to MvxContentPage etc and... background color of navigation page stopped working on Android (I haven't tried on iOS). If i change BarTextColor in App.xaml changes apply, color is changed. if i change BackgroundColor it also works - all application background color is changed. but no matter what value i apply to BarBackgroundColor it is still white.
my App.xaml is as follows:
<?xml version="1.0" encoding="utf-8" ?>
<core:MvxFormsApplication xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:views="clr-namespace:MvvmCross.Forms.Views;assembly=MvvmCross.Forms"
xmlns:viewModels="clr-namespace:MvvmCross.ViewModels;assembly=MvvmCross"
xmlns:core="clr-namespace:MvvmCross.Forms.Core;assembly=MvvmCross.Forms"
xmlns:attributes="clr-namespace:MvvmCross.Forms.Presenters.Attributes;assembly=MvvmCross.Forms"
x:Class="ShowMeTheLogs.Core.FormsApp">
<core:MvxFormsApplication.Resources>
<!--Global Styles-->
<Color x:Key="ColorPrimary">#98C340</Color>
<Color x:Key="ColorError">#CF1212</Color>
<Color x:Key="ColorWarning">#E4AD17</Color>
<Color x:Key="ColorInfo">#1283CF</Color>
<Color x:Key="ColorDebug">#989898</Color>
<Style TargetType="NavigationPage">
<Setter Property="BarBackgroundColor" Value="{StaticResource ColorPrimary}" />
<Setter Property="BarTextColor" Value="White" />
</Style>
<Style x:Key="SubmitButton" TargetType="Button">
<Setter Property="BackgroundColor" Value="{StaticResource ColorPrimary}" />
<Setter Property="TextColor" Value="White" />
</Style>
<Style x:Key="circleButton" TargetType="Button">
<Setter Property="BackgroundColor" Value="{StaticResource ColorPrimary}" />
<Setter Property="BorderRadius" Value="50" />
<Setter Property="WidthRequest" Value="100" />
<Setter Property="HeightRequest" Value="100" />
<Setter Property="TextColor" Value="White" />
<Setter Property="FontSize" Value="50" />
</Style>
<Style x:Key="smallSquareButton" TargetType="Button">
<Setter Property="BackgroundColor" Value="{StaticResource ColorPrimary}" />
<Setter Property="WidthRequest" Value="100" />
<Setter Property="HeightRequest" Value="100" />
<Setter Property="TextColor" Value="White" />
<Setter Property="FontSize" Value="Micro" />
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="VerticalOptions" Value="Center" />
</Style>
</core:MvxFormsApplication.Resources>
</core:MvxFormsApplication>
my App.xalm.cs is the simpliest as it can be:
public partial class FormsApp: MvxFormsApplication
{
public App()
{
InitializeComponent();
}
}
and the simpliest view:
<?xml version="1.0" encoding="utf-8" ?>
<views:MvxContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:views="clr-namespace:MvvmCross.Forms.Views;assembly=MvvmCross.Forms"
x:TypeArguments="viewModels:WebAppListViewModel"
x:Class="ShowMeTheLogs.Core.Views.WebAppListPage"
xmlns:bindings="clr-namespace:MvvmCross.Forms.Bindings;assembly=MvvmCross.Forms"
xmlns:viewModels="clr-namespace:ShowMeTheLogs.Core.ViewModels;assembly=ShowMeTheLogs.Core"
Title="Sample title"
NavigationPage.HasBackButton="False">
<ContentPage.ToolbarItems>
<ToolbarItem x:Name="AddNewApp" Order="Secondary" Text="Dodaj aplikacjÄ™" Priority="0" Command="{bindings:MvxBind NewWebAppCommand}"/>
</ContentPage.ToolbarItems>
<RelativeLayout Padding="0" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<Non relevant="Code" />
</RelativeLayout>
</views:MvxContentPage>
I have literally no idea why it is not working. the only change in androud code was changing class RootActivity: CompatActivity to class RootActivity: MvxFormsAppCompatActivity
have enyone fought this problem before?
packages were obtained from NuGet
- MvvmCross (and MvvmCross.Forms) ver 6.2.2
- Xamarin ver 28.0.0
- Xamarin.Forms ver 3.4.0
In your MainActivity OnCreate method, make sure the two lines setting the Toolbar resource are before the base.OnCreate() call:
protected override void OnCreate(Bundle bundle)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(bundle);
}
https://github.com/MvvmCross/MvvmCross/issues/2301

How to use ResourceDictionary as StaticResource in Windows Phone 8 (element not fount)

I am creating a Windows Phone 8 app. In the app I have a ResourceDictionary defined in a XAML file as:
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="YellowGreen" />
<Setter Property="FontSize" Value="35" />
<Setter Property="TextWrapping" Value="Wrap"/>
</Style>
<Style TargetType="TextBox" x:Key="CommonSetters">
<Setter Property="Width" Value="450"/>
<Setter Property="FontSize" Value="35" />
<Setter Property="Foreground" Value="YellowGreen" />
<Setter Property="Height" Value="100"/>
<Setter Property="Background" Value="Red">
<!--<Setter.Value>
<ImageBrush ImageSource="logo.png" Opacity="0.1"/>
</Setter.Value>-->
</Setter>
</Style>
</ResourceDictionary>
This ResourceDictionary is referenced in App.xaml as:
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone">
<!--Application Resources-->
<Application.Resources>
<local:LocalizedStrings xmlns:local="clr-namespace:Work_Force" x:Key="LocalizedStrings"/>
<ResourceDictionary x:Key="myDict">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resource.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
<Style TargetType="TextBlock" x:Key="NN">
<Setter Property="Width" Value="450"/>
<Setter Property="FontSize" Value="35" />
<Setter Property="Foreground" Value="YellowGreen" />
<Setter Property="Height" Value="100"/>
</Style>
</Application.Resources>
<Application.ApplicationLifetimeObjects>
<!--Required object that handles lifetime events for the application-->
<shell:PhoneApplicationService
Launching="Application_Launching" Closing="Application_Closing"
Activated="Application_Activated" Deactivated="Application_Deactivated"/>
</Application.ApplicationLifetimeObjects>
</Application>
And then the easy part of doing:
Static Resources NN work fine but commonSetters is not working it declared in resourse.xaml.
The way you defined your resources in App.xaml, your 'myDict' resource dictionary is a nested dictionary within Application.Resources default dictionary. I don't know of any syntax how you can reference resources in nested dictionaries in XAML (as I didn't need this ever yet; I think FindResource(...) from code behind can accomplish this). A way to fix your problem is, that you modify the Application.Resources' default dictionary directly to merge with your 'Resources' dictionary. You can do so by modifying the Application.Resources section:
<Application.Resources>
<ResourceDictionary>
<local:LocalizedStrings xmlns:local="clr-namespace:PhoneApp1" x:Key="LocalizedStrings"/>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Note that now you don't have a ReosurceDictionary called 'myDict' anymore. Your 'Resources' dictionary will be directly merged into the default dictionary, that has no key. Then the resource will be resolved correctly.
finally i got the solution it similar like the aspx or html page, where we add the reference of the style in required page
in whereever you, it required to add the reference of the page in page where you have required
<phone:PhoneApplicationPage.Resources>
<ResourceDictionary Source="yourstylepage.xaml"/>
</phone:PhoneApplicationPage.Resources>
put the above code after <phone:PhoneApplicationPage>

Resources