Problem with changing app design at runtime


  • Hi,

    I have a DesignViewModel which takes care of Design changes in my application (Windows & Windows Phone 8.1 Universal app).

    The user can change the whole app design from the app' settings section and I want it to take effect immediately (no need to restart the app for it).

    So, I came with different solutions but failed to get the pretty one to work:

    (For my example, I want to change default text color for the whole application.)

    1 - Changing directly ResourceDictionary entries content:

    If I execute the following code line when my App is starting (before any page is shown) it works fine

    this.Resources["DefaultTextForegroundThemeBrush"] = new SolidColorBrush(Colors.Red);

    Default text color is then set to Red for the entire app.

    If I place this code line anywhere in code AFTER, at least one UI element using this resource is displayed, then I get an ACCESS DENIED exception and the text color is not changed.

    As a B plan, I tried to create a new Dictionary with "DefaultTextForegroundThemeBrush" entry, but when I merge it, it complains because this entry already exists in the initial ResourceDictionary.

    2 -  Because (1) failed, I found no other solution but to override the foreground property of all UI element using default text color in ALL my XAML pages + code behind UI elements.

    So, I set the following XAML attribute in MANY UI elements:

    Foreground="{Binding Source={StaticResource Locator}, Path=DesignVM.ContentTextColor}"

    This is very hard to maintain, especially when adding new UI element, it is easy to forget adding this attribute.

    3 -  Then I thought about another solution based on (2). I thought about declaring a string (either static or const I don't know) in a class. This way:

    public const string MyStaticVar = "{Binding Source={StaticResource Locator}, Path=DesignVM.ContentTextColor}";

    Which would be less painful as I'll only need, in the XAML, to tell that Foreground property "uses" what is in MyStaticVar. The issue is, XAML content is interpreted and if I set



    Foreground="{Binding MyStaticVar}"

    It'll use MyStaticVar content but won't interpret that content. 

    Here are my questions:

    a - From (1), can I get rid of the ACCESS DENIED exception and change those values at runtime?

    b - I really want to get rid of (2), so is it possible to use method (3) somehow?

    Thursday, September 11, 2014 8:07 AM

All replies

  • I guess you could build your own Settings class that e.g. has Properties of Type Color and instead of binding to the Resource Dictionary bind to those values. Your settings class would need to implement the INotifyPropertyChanged interface so that the elements get notified of changes to those properties.

    Thursday, September 11, 2014 8:30 AM
  • This is what method (2) does

    Foreground="{Binding Source={StaticResource Locator}, Path=DesignVM.ContentTextColor}"

    ContentTextColor is a property which returns a SolidColorBrush.

    It works, but I find it really pain full to duplicate over X Xaml pages for each UI elements that are supposed to used the default text color.

    Thursday, September 11, 2014 10:32 AM
  • Did you find a solution for this? I am also having this problem.  I also had to cast the resource as a SolidColorBrush and then change the color property or the changes didn't take effect.

    ((SolidColorBrush)Application.Current.Resources["ApplicationPageBackgroundThemeBrush"]).Color = Colors.Brown;
    This seemed to work for all the brushes except DefaultTextForegroundThemeBrush.  I also tried the new ResourceDictionary approach by adding it to the MergedDictionaries list. I didn't get any errors, but it also didn't apply the styles. I'm assuming editing the MergedDictionaries also have to be done during the app start.  None of my newly merged styles appeared.  I really don't want to have to put a Style attribute on every control as you mentioned. The maintenance would be terrible, especially as more devs start to work on the project.

    Tuesday, December 09, 2014 4:08 AM
  • @R-Enemy:

    Unfortunately, I couldn't have it working. Instead, I HAD TO use the most ugly and not maintainable solution

    => Setting all color attributes (Foreground/Background property) on all UI element by hand (Even if the SolidColorBrush I'm using is binded to a Public Property of my DesignManager it is not elegant enough in my opinion).

    The most elegant solution I've came up with (but couldn't find time to implement it so far), would be to extract ALL UI element default styles (for Textblock, Button, etc... ALL UI elements), rename them and use them and only them in my code. This way, I could define them as I wish. But this will be even more painful to implement even if, in the end, it's the most flexible solution.

    Note: Color properties are the first most annoying things I wanted to setup. But once it was done, I realized their are tons of others issues underneath. The 2nd most annoying things (for my needs) are Sizes (margin, padding, width, height, font size, etc...) If you extract a defaut style of any UI element you'll see many hard coded size values (5, 15, 20, etc...). This is best solution to have inconsistent UI display over devices of different screen resolution. Especially FontSize, the default font size is 11 (or 12). On a small screen phone(~400x600) the text will be readable but on a 1920x1080 screen it will be too small.

    As I said, this are the most annoying things for me, for my needs, as I want my application to look the same on all devices. If a menu icon take 10% of the screen size on small screen device, I want it to look the same on a big screen device, not to have it taking only 2% of the screen size.

    Sorry no to bring you a good answer...

    Tuesday, December 09, 2014 8:11 AM