Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When to programmatically check for theme changes in Windows Phone 8.1

I have a page in a Windows Phone 8.1 app where I have a few components that should be able to have three different color states. They should either be red, blue or the current theme's foreground color.

Therefore, if my app is started using the Dark theme on the phone, and then the user steps out of the app and changes the Light theme, and steps in to my app again, I need to immediately change components that had the old theme's foreground color.

Since the components are supposed to change between different colors (where the theme's foreground color is just one of them) I can't set their Foreground to PhoneForegroundColor in XAML.

What I've done is to add a Resuming event listener that does this:

myTextBlock.Foreground = new SolidColorBrush((Color)Application.Current.Resources["PhoneForegroundColor"]);

But... the Resuming event is fired before the resources of Application.Current are updated, so I end up with the same color as before. If the user steps out again and in again, it'll work since Application.Current.Resources["PhoneForegroundColor"] was updated at some point after the Resuming event the previous time.

Question: When can I first read the updated Application.Current.Resources["PhoneForegroundColor"], since Resuming doesn't seem to be the right place?

Question: Alternatively, is there a way for myTextBlock to inherit another component's ForegroundColor (CSS-ish), so that I can change the myTextBlock.Foreground programatically between Red/Blue/Inherit without having to mind changes to the Phone Theme within my app's lifecycle?

Any suggestions appreciated!

like image 554
andrrs Avatar asked Oct 19 '22 19:10

andrrs


2 Answers

Regarding your first question: The "Resume process" isn't officially documented, but I figured out the following:

Resume gets called on the UI thread. As it is a void returning method, the caller will just continue, when it has an await inside. If you marshall something into the UI thread, it will be in the dispatcher queue and therefor run after the current task (resume).

So I just made this (and it works^^):

private async void App_Resuming(object sender, object e)
{

    var x1 = new SolidColorBrush((Color)Application.Current.Resources["PhoneForegroundColor"]);
    Debug.WriteLine(x1?.Color.ToString());

    // Await marshalls back to the ui thread,
    // so it gets put into the dispatcher queue
    // and is run after the resuming has finished.
    await Task.Delay(1);

    var x2 = new SolidColorBrush((Color)Application.Current.Resources["PhoneForegroundColor"]);
    Debug.WriteLine(x2?.Color.ToString());
}

Regarding your second question: You could introduce a "ValueProvider" in your app.xaml, that registers for the resume event and just provides a dependency property with the current color.

You will still have to set that on any TextBlock you want to use that in, but at least directly in XAML. This might work for styles too, but did not try that.

Sample implementation....

Provider:

public class ColorBindingProvider : DependencyObject
{
    public ColorBindingProvider()
    {
        App.Current.Resuming += App_Resuming;
    }

    private async void App_Resuming(object sender, object e)
    {
        // Delay 1ms (see answer to your first question)
        await Task.Delay(1);

        TextColor = new SolidColorBrush((Color)Application.Current.Resources["PhoneForegroundColor"]);
    }

    public Brush TextColor
    {
        get { return (Brush)GetValue(TextColorProperty); }
        set { SetValue(TextColorProperty, value); }
    }

    public static readonly DependencyProperty TextColorProperty =
        DependencyProperty.Register("TextColor", typeof(Brush), typeof(ColorBindingProvider), new PropertyMetadata(null));
}

App.xaml:

<Application.Resources>
    <local:ColorBindingProvider x:Name="ColorBindingProvider" TextColor="{StaticResource PhoneForegroundBrush}" />
</Application.Resources>

MainPage.xaml:

<TextBlock Text="Hey ho let's go" Foreground="{Binding TextColor, Source={StaticResource ColorBindingProvider}}" />
like image 151
Kai Brummund Avatar answered Oct 22 '22 10:10

Kai Brummund


In Windows Phone 8.1 you are able to determine the selected theme via Application.Current.RequestedTheme witch will return a value of the enum Windows.UI.Xaml.ApplicationTheme.

example:

public static string GetImagePath(){
    // if the background color is black, i want a white image
    if(Application.Current.RequestedTheme == ApplicationTheme.Dark)
        return "ms-appx:///Assets/img_light.jpg";

    // if the background color is white, i want a dark image
    return "ms-appx:///Assets/img_dark.jpg";
}

side note: you are even able to change the selected theme with Application.Current.RequestedTheme

more details: https://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.application.requestedtheme

like image 40
szuuuken Avatar answered Oct 22 '22 09:10

szuuuken