Reputation: 1338
I would like to use a DynamicResource in a Style for only 1 platform (f.e. Android) without having to do something in the code-behind.
I've seen a solution which works if you want to implement something for multiple platforms, but when I try to use it without one of the platforms (like the xaml below), the app crashes on a NullReferenceException when I run it on a device with a different platform (so in this example iOS).
<Style TargetType="ContentPage" ApplyToDerivedTypes="True">
<Setter Property="BackgroundColor" Value="{DynamicResource PageBackgroundColor}"/>
<Setter Property="Padding" Value="{OnPlatform Android={DynamicResource ContentPagePadding}}"/>
</Style>
I've also tried numeral solutions along the lines of the snippet below, which also results in a crash when I run it on a device with the same platform (so in this example Android).
<Style TargetType="ContentPage" ApplyToDerivedTypes="True">
<Setter Property="BackgroundColor" Value="{DynamicResource PageBackgroundColor}"/>
<Setter Property="Padding" >
<Setter.Value>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="Android">
<DynamicResource Key="ContentPagePadding"/>
</On>
</OnPlatform>
</Setter.Value>
</Setter>
</Style>
So at this point I hope someone has an idea how I would be able to do this (without the app crashing instantly). But I'm afraid this (currently) isn't possible. Anyways, thanks in advance for the help.
EDIT 1: I've noticed the 2nd solution does seem to work with a static resource, but the resources I want to use are dynamic, so that isn't much of an option, though I am curious why staticresources do work and dynamic resources don't.
Upvotes: 2
Views: 640
Reputation: 21321
One way or another, currently you have to do something, somewhere in code. Here is an alternative that for some uses is more convenient than having to change it in the code behind of that page.
If you DON'T need it to dynamically change after a page has been loaded, you can "cheat":
Declare it as static. Give it some initial value. Then change it in code to the desired value before the page is loaded.
I've tested it with fontsize, but should work just as well with padding.
App.xaml:
<Application.Resources>
<x:Double x:Key="MyFontSize">10</x:Double>
</Application.Resources>
App.xaml.cs:
public App()
{
InitializeComponent();
LoadMyPage(50.0);
ReloadMyPageDeferred(25.0, 3);
ReloadMyPageDeferred(10.0, 6);
}
public void ReloadMyPageDeferred(double newFontSize, int seconds)
{
Device.BeginInvokeOnMainThread(async () => {
await Task.Delay(seconds * 1000);
LoadMyPage(newFontSize);
});
}
public void LoadMyPage(double newFontSize)
{
// To be safe, use the expected type. For fontsize, Use "(double)..." if source isn't already a double.
Application.Current.Resources["MyFontSize"] = newFontSize;
MainPage = new MyPage();
}
MyPage.xaml:
<ContentPage.Resources>
<Style TargetType="Label">
<Setter Property="FontSize">
<Setter.Value>
<OnPlatform x:TypeArguments="x:Double">
<On Platform="Android" Value="{StaticResource MyFontSize}"/>
</OnPlatform>
</Setter.Value>
</Setter>
</Style>
</ContentPage.Resources>
This demo shows MyPage three times, with a 3 second delay between each load. FontSize is different each time - the "StaticResource" is altered before the page's XAML loads via new MyPage()
s call to InitializeComponent
.
In the simplest case, where you had made it a DynamicResource only so that your app can give it a value ONCE at runtime, this can be done in your app.xaml.cs, and then all other pages "just work" - because the StaticResource now has the desired value.
LIMITATION: I've tested this in a Release build on Android, both with and without AOT/LLVM compilation, but I have not verified that it works on all platforms when you've turned on all buid optimizations. It relies on StaticResource being "resolved" at the time that you call new MyPage()
, not before that.
Have not yet tested on iOS or UWP.
Upvotes: 1