Content page property not set with implicit style - xaml

Using Prism.Forms 6.2 and Xamarin.Forms 2.3.3.118 pre-1 when I set the content page padding in the application resource file it is not followed globally only for the content page padding. All other resource properties are flowing correctly. Here is my code for the app.xaml:
<?xml version="1.0" encoding="utf-8"?>
<prism:PrismApplication xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyNamespace.App"
xmlns:prism="clr-namespace:Prism.Unity;assembly=Prism.Unity.Forms"
xmlns:local="clr-namespace:MyNamespace;assembly=MyNamespace">
<prism:PrismApplication.Resources>
<!-- Application resource dictionary -->
<ResourceDictionary>
<converter:DebuggingConverter x:Key="localDebuggingConverter"/>
<local:ItemTappedEventArgsToItemTappedConverter x:Key="SelectedItemConverter" />
<Style TargetType="Label">
<Setter Property="FontSize" >
<Setter.Value>
<!--iOS default is 17 and is not the same size as android 14. If FontSize is left at default it will be larger on iOS than android-->
<OnPlatform x:TypeArguments="x:Double"
iOS="14"
Android="14">
</OnPlatform>
</Setter.Value>
</Setter>
<Setter Property="VerticalOptions" Value="Center">
</Setter>
</Style>
<Style TargetType="ContentPage">
<Setter Property="Padding">
<Setter.Value>
<OnPlatform x:TypeArguments="Thickness"
iOS="5, 28, 5, 5"
Android="5, 8, 5, 5"
WinPhone="5, 8, 5, 5" />
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</prism:PrismApplication.Resources>
</prism:PrismApplication>
Here is my xaml view:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
xmlns:local="clr-namespace:MyNamespace;assembly=MyNamespace"
prism:ViewModelLocator.AutowireViewModel="True"
x:Class="MyNamespace.Views.ChooseProfileView">
<!--<ContentPage.Padding>
If I set the content padding this way it is rendered correctly. When this is commented out as it is now the padding is not set by the application resource (implicit style).
<OnPlatform x:TypeArguments="Thickness"
iOS="5, 28, 5, 5"
Android="5, 8, 5, 5"
WinPhone="5, 8, 5, 5" />
</ContentPage.Padding> -->
<ContentPage.Content>
<!-- whatever content. The padding set here is displayed correctly-->
</ContentPage.Content>
</ContentPage>
Any ideas what is wrong?

TargetType in style is set to ContextPage but the real type is ChooseProfileView.
Xamarin.Forms.Style.TargetType Property
Developers should be aware that implicit styles are only applied to the specific type that is described by Style.TargetType, and not to types that inherit from it.

Related

Two titleviews in dotnet maui

Im trying to create a Maui application with a dynamic Tabbar which should also be navigateable (and thus consist of NavigationPages). When I switch to a different tab, everything works fine, but as soon as is switch to an alreay visited tab, two titlebars appear:
One with the style i have defined (upper) and a default titlebar (lower). How can I remove the default titlebar?
Important code:
App.xaml.cs:
MainPage = new NavigationPage(new AppShell());
Page1:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:viewModels="clr-namespace:foo"
xmlns:converters="clr-namespace:foo.Converters"
x:Class="foo.MainPage"
NavigationPage.HasBackButton="False"
Title="foo"
Loaded="ContentPage_Loaded">
-- Content --
</ContentPage>
Page2:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="foo.Views.fooPage"
Title="foo">
-- Content --
</ContentPage>
NavigationbarStyle:
<ResourceDictionary xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="foo.Resources.Styles.NavigationbarStyle">
<Style TargetType="NavigationPage">
<Setter Property="BarBackground" Value="{DynamicResource NavigationBarBackgroundColor}"/>
<Setter Property="BarTextColor" Value="White"/>
</Style>
</ResourceDictionary>
AppShell (more tabs are added later on):
<Shell
x:Class="foo.AppShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:foo"
xmlns:views="clr-namespace:foo.Views"
Shell.FlyoutBehavior="Disabled">
<TabBar x:Name="MainTabBar">
<ShellContent Title="Home"
Icon="alert_icon_2_neg.png"
ContentTemplate="{DataTemplate views:StartPage}">
</ShellContent>
</TabBar>
</Shell>

How do I create constants to be used in Xamarin.Forms XML

As an Android developer I'm used to work with #dimen/-constants in Androids XML. I find this future useful because it allows me to easily change multiple places that should have the same pixel-length together.
Does Xamarin.Forms have a similar features that I can use?
Well what you looking for are ResourceDictionaries
XAML resources are definitions of objects that can be shared and re-used throughout a Xamarin.Forms application.
These resource objects are stored in a resource dictionary.
A ResourceDictionary is a repository for resources that are used by a Xamarin.Forms application. Typical resources that are stored in a ResourceDictionary include styles, control templates, data templates, colours, and converters.
In XAML, resources that are stored in a ResourceDictionary can then be retrieved and applied to elements by using the StaticResource markup extension. In C#, resources can also be defined in a ResourceDictionary and then retrieved and applied to elements by using a string-based indexer. However, there's little advantage to using a ResourceDictionary in C#, as shared objects can simply be stored as fields or properties, and accessed directly without having to first retrieve them from a dictionary.
Creating and Consuming a ResourceDictionary
Resources are defined in a ResourceDictionary that is then set to one of the following Resources properties:
The Resources property of any class that derives from Application.
The Resources property of any class that derives from VisualElement
A Xamarin.Forms program contains only one class that derives from Application but often makes use of many classes that derive from VisualElement, including pages, layouts, and controls. Any of these objects can have its Resources property set to a ResourceDictionary. Choosing where to put a particular ResourceDictionary impact where the resources can be used:
Resources in a ResourceDictionary that is attached to a view such as Button or Label can only be applied to that particular object, so this is not very useful.
Resources in a ResourceDictionary attached to a layout such as StackLayout or Grid can be applied to the layout and all the children of that layout.
Resources in a ResourceDictionary defined at the page level can be applied to the page and to all its children.
Resources in a ResourceDictionary defined at the application level can be applied throughout the application.
The following XAML shows resources defined in an application level ResourceDictionary in the App.xaml file created as part of the standard Xamarin.Forms program:
<Application ...>
<Application.Resources>
<ResourceDictionary>
<Color x:Key="PageBackgroundColor">Yellow</Color>
<Color x:Key="HeadingTextColor">Black</Color>
<Color x:Key="NormalTextColor">Blue</Color>
<Style x:Key="LabelPageHeadingStyle" TargetType="Label">
<Setter Property="FontAttributes" Value="Bold" />
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="TextColor" Value="{StaticResource HeadingTextColor}" />
</Style>
</ResourceDictionary>
</Application.Resources>
Beginning in Xamarin.Forms 3.0, the explicit ResourceDictionary tags are not required. The ResourceDictionary object is created automatically, and you can insert the resources directly between the Resources property-element tags:
<Application ...>
<Application.Resources>
<Color x:Key="PageBackgroundColor">Yellow</Color>
<Color x:Key="HeadingTextColor">Black</Color>
<Color x:Key="NormalTextColor">Blue</Color>
<Style x:Key="LabelPageHeadingStyle" TargetType="Label">
<Setter Property="FontAttributes" Value="Bold" />
<Setter Property="HorizontalOptions" Value="Center" />
<Setter Property="TextColor" Value="{StaticResource HeadingTextColor}" />
</Style>
</Application.Resources>
Each resource has a key that is specified using the x:Key attribute, which becomes it dictionary key in the ResourceDictionary. The key is used to retrieve a resource from the ResourceDictionary by the StaticResource markup extension, as demonstrated in the following XAML code example that shows additional resources defined within the StackLayout:
<StackLayout Margin="0,20,0,0">
<StackLayout.Resources>
<ResourceDictionary>
<Style x:Key="LabelNormalStyle" TargetType="Label">
<Setter Property="TextColor" Value="{StaticResource NormalTextColor}" />
</Style>
<Style x:Key="MediumBoldText" TargetType="Button">
<Setter Property="FontSize" Value="Medium" />
<Setter Property="FontAttributes" Value="Bold" />
</Style>
</ResourceDictionary>
</StackLayout.Resources>
<Label Text="ResourceDictionary Demo" Style="{StaticResource LabelPageHeadingStyle}" />
<Label Text="This app demonstrates consuming resources that have been defined in resource dictionaries."
Margin="10,20,10,0"
Style="{StaticResource LabelNormalStyle}" />
<Button Text="Navigate"
Clicked="OnNavigateButtonClicked"
TextColor="{StaticResource NormalTextColor}"
Margin="0,20,0,0"
HorizontalOptions="Center"
Style="{StaticResource MediumBoldText}" />
</StackLayout>
For more detailed information kindly take a look here
Apart from the StaticResource as mentioned above, 2 other ways to do it.
First one is, Having static class for constants and refer them in the XAML.
public static class GlobalSetting
{
public static double ImageRotation { get { return 180; } }
}
In the Xaml, you need to add this namespace in the page directive,
xmlns:gb="clr-namespace:XXXX.StaticData"
and use the constant in the xaml code as below,
<Image Source="icon_back.png" Rotation="{x:Static gb:GlobalSetting.BackImageRotation}" HeightRequest="24" </Image>
Second approach is, having a constant parameter in the BaseViewModel, and binding them in the Xaml code.
Sounds to me like you want to define constants/styles in a ResourceDictionary:
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/xaml/resource-dictionaries.
In the ResourceDictionary you can define your constants/styles by key, in your XAML you can then refer to them as follows:
Color={StaticResource MyColorFromDictionary}

Arithmetic Operations inside XAML Resource Dictionary

What I want to do
I've been exploring XAML Resource Dictionaries recently. They are very powerful, but in order to cut down (even further) on the changes that would need to be made to accommodate any modifications, I'd like to use some basic arithmetic operations to change the HeightRequest property of an Entry.
I'm already making good use of OnPlatform and OnIdiom for different aspects, like FontSize.
For the iOS Platform, I'd like to make the HeightRequest of an entry 20+(FontSize). The FontSize is already set using OnIdiom (it's slightly increased for tablets).
In a perfect world, the core thing which I'm trying to do might look something like
<Setter Property="HeightRequest" Value="{DynamicResource StandardFontSize}+10">
What "works"
I have a working solution if I use a combination of OnIdiom and OnPlatform.
<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamarinDesigner.App"
xmlns:local="clr-namespace:XamarinDesigner"
>
<Application.Resources>
<ResourceDictionary>
<OnIdiom x:Key="StandardFontSize" x:TypeArguments="x:Double" Tablet="22" Phone="18"/>
<Style x:Key="MyEntry" TargetType="Entry">
<Setter Property="FontSize" Value="{DynamicResource StandardFontSize}"/>
<Setter Property="HeightRequest">
<Setter.Value>
<OnIdiom x:TypeArguments="x:Double">
<OnIdiom.Phone>
<OnPlatform x:TypeArguments="x:Double" iOS="30"/>
</OnIdiom.Phone>
<OnIdiom.Tablet>
<OnPlatform x:TypeArguments="x:Double" iOS="40"/>
</OnIdiom.Tablet>
</OnIdiom>
</Setter.Value>
</Setter>
<Setter Property="VerticalOptions" Value="Center"/>
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>
With this 'solution' - I need to set the value explicitly and do the calculations myself. While this works, I'd like to be able to perform a basic arithmetic operation to find the value of FontSize, and add some number to it.
What I've tried
In another attempt I've made, I've found a converter and tried to adapt it to my use case. While there is no intellisense or build/compile errors, the app crashes immediately after opening. The .cs file for ArithmeticConverter can be found in the link above.
<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamarinDesigner.App"
xmlns:local="clr-namespace:XamarinDesigner"
>
<Application.Resources>
<local:ArithmeticConverter x:Key="AScript"/>
<ResourceDictionary>
<OnIdiom x:Key="StandardFontSize" x:TypeArguments="x:Double" Tablet="22" Phone="18"/>
<Style x:Key="MyEntry" TargetType="Entry">
<Setter Property="FontSize" Value="{DynamicResource StandardFontSize}"/>
<Setter Property="HeightRequest" Value="{Binding Converter={StaticResource AScript},ConverterParameter=Int32.Parse(20+{DynamicResource StandardFontSize}}"/>
<Setter Property="VerticalOptions" Value="Center"/>
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>
I don't fully understand the use of converters, and {Binding} inside of a value in App.xaml is also something that is new to me. Looking at the example provided with the converter, I think I'm close to being correct, and may just need a push in the right direction?
Is it possible to do this basic sort of arithmetic function in the App.xaml alone(or with the use of a converter)? I'm hoping to contain as much as I can to this file.
Other solutions I've found in my search have mentioned the use of a viewmodel, but this is a 'global' change I want to apply to every entry per platform/idiom, so I can't see how that adaption might work.
Thanks for your time!
One of the reason your app is crashing is because Converter is outside the ResourceDictionary.
Solution 1
Binding should be used only when there is a BindingContext assigned, hence you need to assign it in cs file.
App.cs:
public App()
{
InitializeComponent();
BindingContext = new { EntryHeightRequest = 10 };
MainPage = ...
}
App.xaml:
<ResourceDictionary>
<local:ArithmeticConverter x:Key="AScript"/>
<OnIdiom x:Key="StandardFontSize" x:TypeArguments="x:Double" Tablet="22" Phone="18"/>
<Style x:Key="MyEntry" TargetType="Entry">
<Setter Property="FontSize" Value="{DynamicResource StandardFontSize}" />
<Setter Property="HeightRequest" Value="{Binding EntryHeightRequest, Converter={StaticResource AScript},ConverterParameter="{StaticResource StandardFontSize}"/>
<Setter Property="VerticalOptions" Value="Center"/>
</Style>
</ResourceDictionary>
ArithmeticConverter.cs:
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value is int constant && parameter is OnIdiom<double> dynamicSize)
return constant + dynamicSize.GetValue();
return -1;
}
OnIdiomExtension:
public static T GetValue<T>(this OnIdiom<T> idiom)
{
switch(Device.Idiom)
{
case TargetIdiom.Phone:
return idiom.Phone;
case TargetIdiom.Desktop:
return idiom.Desktop;
case TargetIdiom.Tablet:
return idiom.Tablet;
case TargetIdiom.TV:
return idiom.TV;
case TargetIdiom.Watch:
return idiom.Watch;
default:
throw new NotSupportedException();
}
}
Beware: When I tried, BindingContext is passed to ResourceDictionary(but this post contradicts it, may be they changed?)
Solution 2
Similar to Solution 1 but instead of setting BindingContext you can use OnIdiom on HeightRequest with default value.
<Setter Property="HeightRequest" Value="{OnIdiom Default=10, Converter={StaticResource AScript}, ConverterParameter={StaticResource StandardFontSize}}" />

Windows Phone: how to change the Application style programmatically

In my Windows Phone 8 app, I have some implicit styles defined in a xaml file at the location /Styles/DefaultStyles.xaml
I have a similar file but with different colors, fonts, etc ... defined at /Styles/GreenStyles.xaml.
I reference the default style file in my App.xaml as follows :
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Styles/DefaultStyles.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
I want to make my app switch its implicit styles from the other styles file (GreenStyles) programmatically.
How can I achieve this ?
**
UPDATE:
I manged to change the source of the resource dictionary as follows:
ResourceDictionary style = App.Current.Resources.MergedDictionaries.ToList()[0];
string source = String.Format("/ApplicationName;component/Styles/GreenStyles.xaml");
style.Source = new Uri(source, UriKind.Relative);
Note: the word component must be written like that to avoid exceptions
Now I have an issue:
only the Implicit styles (the ones that do not have a x:Key attribute) are switched when the source of the dictionary changes.
any other style with a specified key and defined twice (with different attributes) in both files, will not be reflected in the UI.
so if I have these files:
DefaultStyles.xaml:
<Style x:Key="MainGrid" TargetType="Grid">
<Setter Property="Background" Value="Red"/>
</Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Red"/>
<Setter Property="FontSize" Value="24"/>
</Style>
</ResourceDictionary>
And:
GreenStyles.xaml:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone">
<Style x:Key="MainGrid" TargetType="Grid">
<Setter Property="Background" Value="Green"/>
</Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Green"/>
<Setter Property="FontSize" Value="24"/>
</Style>
</ResourceDictionary>
and I switched the source to point to GreenStyles.xaml, any Grid with the style MainGrid will still have it's background to Red.
What can be the reason for this ?
You can try using the approach Jeff Wilcox described here: http://www.jeff.wilcox.name/2012/01/phonethememanager/
Alternative approach is described here for Silverlight and I'm not sure if this will work on Windows Phone (though they share some codebase):
http://silverlightips.wordpress.com/2010/04/29/change-themestyle-using-merged-dictionaries/
Both of the ways are not easy if you have a large app and you may consider another option like (call me crazy)
<Button Style="{Binding Locator.Theme, Converter={StaticResource StyleThemeConverter}, ConverterParameter=RefreshButtonStyle}"
Hope this helps.

In XAML, is it possible to define a global constant style without specifying the TargetType

I would like to define my logo color as a style then apply that color wherever. Something like this:
<Style x:Name="LogoBlue">
<Setter Property="Background" Value="#607C8C" />
</Style>
<TextBlock Background="{StaticResource LogoBlue}">Blah Blah</TextBlock>
Is it possible to define a color constant as a static resource?
Define a brush as a resource in your App.xaml, then you can refer to it by its key.
As the colour is a fixed colour the PresentationOptions allows more efficient use of the brush as you will not change it's colour.
<Application x:Class="WpfApplication1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="PresentationOptions"
StartupUri="MainWindow.xaml">
<Application.Resources>
<SolidColorBrush x:Key="LogoBlue" Color="#607C8C" PresentationOptions:Freeze="True"/>
</Application.Resources>
</Application>