Open SetTrend opened 4 years ago
There are a few things here, so I'll create a list.
ThemeResource
reference are colors, they can also be styles, strings, numbers. So when removing ThemeResource
references, ANY theme change would requireyou to reevaluate any resources, not just colors. That would have a significant performance impact.@chingucoding, you are right. I chose this repository mainly because most of my recent UWP proposals got forwarded from UWP to ProjectReunion. I'm not sure about the detailed reasoning for separating UWP from ProjectReunion. So, this time, I just wanted to preemptively obviate the shift ... wrong choice again, I'm afraid π
Regarding your remarks:
As external app programmer I don't have insights of the intrinsics of Windows Runtime and the XAML JIT compiler. Yet, wenn the XAML JIT compiler recognizes a single theme color reference in the tree, that's sufficient information to be stored to re-evaluate the tree when the user session theme changes. The tree must then be re-evaluated anyway.
The XAML JIT compiler may internally create a separate cache for theme colors when it parses the tree, so it may optimize re-evaluation.
Would you want to elaborate: Would that make a significant change to my proposal?
My proposal is to remove consideration about a theme completely from the app programmer.
My suggestion of a corresponding event to add is just a proposal. Any suggestion for a better place to put it is highly welcome.
In that special case you are referring to, I wouldn't call these colors "theme" colors. And I wouldn't code them to be theme colors. They simply are colors accidentally having the same value as some theme color (of a potentially unused theme).
As external app programmer I don't have insights of the intrinsics of Windows Runtime and the XAML JIT compiler. Yet, wenn the XAML JIT compiler recognizes a single theme color reference in the tree, that's sufficient information to be stored to re-evaluate the tree when the user session theme changes. The tree must then be re-evaluated anyway.
The XAML JIT compiler may internally create a separate cache for theme colors when it parses the tree, so it may optimize re-evaluation.
I hope that the not the entire tree will be reevaluated if the entire tree only contains a single theme resource references as this would be very inefficient.
Would you want to elaborate: Would that make a significant change to my proposal?
I just wanted to point out that there is more to theming than just the user changing the theme. You might did not know that or have forgotten it and I was not sure, so better safe then sorry. Especially since your whole argument is based on the assumption that the only reason for a theme change is the user changing the system wide theme.
Currently, this results in a noticable stutter. The system has to (a) search for ThemeResource references first and then (b) to redraw the application anyway. I believe that step (a) is an unnecessary step, just wasting time.
If you don't know how the XAML runtime works, why do you claim that it does that when the theme changes? The noticable stutter is also not caused by step (a), see this issue.
My proposal is to remove consideration about a theme completely from the app programmer.
My suggestion of a corresponding event to add is just a proposal. Any suggestion for a better place to put it is highly welcome.
If you need to know when the user theme changes, you can always use the UISettings class which has an event that notifies you when theme colors changed. I would not add a new event to UIElements that get's raised when the theme changed.
In that special case you are referring to, I wouldn't call these colors "theme" colors. And I wouldn't code them to be theme colors. They simply are colors accidentally having the same value as some theme color (of a potentially unused theme).
It is not that special if you look at all the apps that have a dedicated theme setting. You might think it is a special corner case, but the fact is that a lot of apps have a setting to let users change the theme in app overriding the system theme. I am not sure why you would argue it is not a "theme color" if it relies setting the theme on individual elements. Guess we have different opinions what is a theme and what is not.
Please accept my apoligies if my wording may sound unfriendly. This is not my native tongue. I'm in no way aggressive. I'm just trying to argue.
I hope that the not the entire tree will be reevaluated if the entire tree only contains a single theme resource references as this would be very inefficient.
Absolutely. I believe this to be a Windows Runtime implementation detail, though. That kind of optimization is deterministic and not a subject for the app programmer.
Imagine a Page
with SystemChromeMediumLowColor
. All controls therein with Alpha > 0 (or Acrylic effect applied) would need to be re-rendered when the user session theme changes. The controls to re-render can be determined deterministically.
since your whole argument is based on the assumption that the only reason for a theme change is the user changing the system wide theme.
We're on the same page here. In my original message I pointed out that "When Microsoft Windows Themes are enabled, the [system] theme [automatically] changes every couple of minutes."
The noticable stutter is also not caused by step (a), see this issue.
Ah, I see. OK .. This'll surely invalidate the "sluggish" attribute in my proposal then :blush:
If you need to know when the user theme changes, you can always use the UISettings class which has an event that notifies you when theme colors changed. I would not add a new event to UIElements that get's raised when the theme changed.
Perfect!
Guess we have different opinions what is a theme and what is not.
Probably, yes. If I'd be a user having selected the "High Contrast" theme due to disabilities, I wouldn't consider an app not following that theme "theming". I'd rather call it "not theming but following its own way of rendering content".
Please accept my apoligies if my wording may sound unfriendly. This is not my native tongue. I'm in no way aggressive. I'm just trying to argue.
I hope I don't sound to unfriendly either since this is not my native tongue either. If I sound to unfriendly, I am sorry about this.
Absolutely. I believe this to be a Windows Runtime implementation detail, though. That kind of optimization is deterministic and not a subject for the app programmer.
Imagine a Page with SystemChromeMediumLowColor. All controls therein with Alpha > 0 (or Acrylic effect applied) would need to be re-rendered when the user session theme changes. The controls to re-render can be determined deterministically.
I would definitely not consider that an implementation detail. While we don't know it now, it surely makes a huge difference when talking about changes to that. Imagine setting colors statically and only have a single textblock on your page use a theme resource. With your proposal, the entire UI would be redrawn which can be painstakingly expensive. With themeresources, we would be able to only update a single component.
We're on the same page here. In my original message I pointed out that "When Microsoft Windows Themes are enabled, the [system] theme [automatically] changes every couple of minutes."
I would fit this under changing system setting. Your proposal does not account for in app theme changes (e.g. through the apps settings) at all.
Probably, yes. If I'd be a user having selected the "High Contrast" theme due to disabilities, I wouldn't consider an app not following that theme "theming". I'd rather call it "not theming but following its own way of rendering content".
Depends on what the settings of the app is. If you open Microsoft ToDo and change the theme to light theme, I would definitely consider that theming, even if you change your system theme to dark and ToDo is still rendering in light theme. If you don't consider that theming, I would definitely update your proposal to make it clear what is excluded here. In the current form, you would pretty much break in app theming with removing themeresources or make a noticable decrease of performance when changing themes.
To me it seems like our only diverging perspectives is in our notion of a "theme":
I'm considering a "theme" to be a system wide setting (based on the fact that users may set their personal preference in Windows > Settings > Personalization
) while you are considering a "theme" to be rather a local app setting; a decision left to the app author, not the system.
To this regard, here's a quote from the MS documentation on XAML theme resources:
Theme resources in XAML are a set of resources that apply different values depending on which system theme is active. There are 3 themes that the XAML framework supports: "Light", "Dark", and "HighContrast".
I'd humbly like to put your focus on the words "is active" in the above quote.
A local app theme, being independant from the current system color theme, I would rather call a "skin". And that's what a common ResourceDirectory
is providing (again, here's a quote from the MSDN documentation on ResourceDictionary and XAML resource references:
Resources are typically definitions of some object that you expect to use more than once. To refer to a XAML resource later, you specify a key for a resource that acts like its name. You can reference a resource throughout an app or from any XAML page within it.
The sole fact that the app author may choose a color that happens to be similar or even equal to that of some system theme color is - from my personal perspective - not making it a theme color per se. It's just some color with no special meaning.
To this regard I tend to consider the RequestedTheme
property an anti-pattern, except perhaps for a quite marginal number of System Theme Preview apps.
If we just take my point of view about "themes" for a moment, then ...
StaticResource
properties identified as theme brush can automatically and internally be converted to ThemeResources
by Windows Runtime
(They wouldn't actually be "converted" but simply the ThemeResource
logic would be applied.)ThemeResources
being identified automatically or manually.ThemeResources
But isn't it surprising then, that every framework element has a "RequestedTheme" property? Would you call them "RequestedSkin" then?
If you look at the RequestedTheme property on the Application class, it says:
Gets or sets a value that determines the light-dark preference for the overall theme of an app.
So I would argue theme is not only about what the system dictates, but also what the app requests, as indicated by multiple occurrences of the word theme in properties.
But I guess, if you consider RequestedTheme an antipattern, there isn't much to discuss here about that term. The only thing I can say is that I heard a lot of people refer to the app theme as a theme and part of the theming experience, not just a skin or saying that only the option in the system is a "theme".
If we take your definition of "theme", what would happen with changing the requested theme property then? How would that be respected if in your proposal, if that wouldn't suffice your definition of "theme" change?
what would happen with changing the requested theme property then? How would that be respected if in your proposal?
Given that programmers would refrain from using Theme color references as static resource brushes, everything would stay the same.
Using Theme color brushes for static colors values doesn't make sense: If the user changed the Theme while the app is running, StaticResource
Theme color references wouldn't update. When the app is then closed and relaunched, then the StaticResource
will finally show the new color. That's not expected behaviour.
Regarding RequestedTheme
, perhaps we can agree on this:
The runtime alone is responsible for defining, providing and maintaining Theme colors. Theme colors are never sourced from anything else but the runtime system.
So, a programmer should ask himself: Do I want to rely on any color the system provides for a given moniker? Or do I not want to cede control to the system?
If a programmer does not want to rely on the system providing any arbitrary color for a given moniker, so if (s)he wants to retain control over the colors to display in an app, (s)he shouldn't use Theme colors but instead create their own monikers and color definitions. That'll make sure that these app colors won't change, whatever colors the runtime system may provide for a given Theme moniker at any time.
For example:
If the Windows Runtime team decided to change any of the system Theme colors - would the app want to follow that change?
So, if ApplicationPageBackgroundThemeBrush
would be changed to a light green for the Light
theme with an upcoming version of Windows Runtime due to fashion concerns - would the app want to follow that change? Would it want to be displayed in a greenish fashion? Or would it rather want to keep its (app specific) white background color? Then it shouldn't use Theme color monikers right from the beginning.
So, the RequestedTheme
property is, or should be regarded as, a misconception of Theme colors, because it denies the thought of "give me any color the runtime feels appropriate for that moniker".
Using Theme color brushes for static colors values doesn't make sense: If the user changed the Theme while the app is running, StaticResource Theme color references wouldn't update. When the app is then closed and relaunched, then the StaticResource will finally show the new color. That's not expected behaviour.
Except that their are a system colors that are defined as theme resource, but have the same value in all themes. I don't want to have a theme change cause those resources to be reevaluated. But that is a corner case.
The runtime alone is responsible for defining, providing and maintaining Theme colors. Theme colors are never sourced from anything else but the runtime system.
And what if I write my own control? Then I am unable to define custom themeable colors? Or do I have to rely on the limited number of existing theme resources? In that case, a lot of UI libraries and apps will break, which is a terrible thing to do.
Quite frankly, you seem to ignore or forget what requestedtheme does. It OVERRIDES the theme of that element. It's essentially removing that element from the list of elements listening to the system theme and let that element have it's own theme lifetime.
So, if ApplicationPageBackgroundThemeBrush would be changed to a light green for the Light theme with an upcoming version of Windows Runtime due to fashion concerns - would the app want to follow that change? Would it want to be displayed in a greenish fashion? Or would it rather want to keep its (app specific) white background color? Then it shouldn't use Theme color monikers right from the beginning.
If a developer dislikes the choice of the light theme version of that brush, they can simply override the value for that theme and still get the theming experience?
So, the RequestedTheme property is, or should be regarded as, a misconception of Theme colors, because it denies the thought of "give me any color the runtime feels appropriate for that moniker".
That might fit in with your perception of the word theme, but any other person would say that that statement is just wrong. RequestedTheme is about asking to render that control how it would like in a specific theme (Light or Dark) or follow the system theme.
You say theme colors are only defined by the system, and you will need to find a new description for all colors WinUI, WCT and all the other libraries define for the light, dark and high contrast theme. If you want to do that sure, but I think you will create a lot of confusion if suddenly a resource defined in the ThemeDictionary with key "Light" is not a light theme resource.
Also, you should update your proposal to include your updated thoughts.
Not sure how this is specific to ProjectReunion, this is specifically about the UWP UI framework, not the UWP app model/sandbox. @jevansaks Does it make sense to move this to the WinUI repo?
@chingucoding Sure I can move this to WinUI if it won't disrupt this conversation. I have limited experience with this issue transfer feature. :)
And what if I write my own control? Then I am unable to define custom themeable colors?
I'm not sure if I'm getting your concern straight.
For your custom control you can still write as many themable styles as you like. You'd be using ResourceDictionary.ThemeDictionaries
.
Also, you should update your proposal to include your updated thoughts.
Yes, I agree, I'm having the same thoughts.
Today, I noticed that a more straightforward solution to my proposal may be not to drop ThemeResource
but instead block StaticResource
from referencing themed resources.
@chingucoding Sure I can move this to WinUI if it won't disrupt this conversation. I have limited experience with this issue transfer feature. :)
@jevansaks Sure, please go ahead!
For your custom control you can still write as many themable styles as you like. You'd be using ResourceDictionary.ThemeDictionaries.
Right, so anything defined in a theme dictionary will be respect as theme resource. Maybe misread your comments then.
Today, I noticed that a more straightforward solution to my proposal may be not to drop ThemeResource but instead block StaticResource from referencing themed resources.
That sounds like a way more reasonable approach to the problem!
From our conversation (which was utterly valuable to me BTW - thank you for taking all this time and effort so far πππ ) and a number of other issues related to theming and how resources are addressed, e.g.:
... I feel that the way how theming, styling and resource references are implemented may benefit from being revamped. After studying UWP documentation for the last couple of months, it looks to me like this area is a muddle, having adopted a number of quirks over time to overcome design flaws that have been originally introduced. I believe it requires a redo.
(I'm not linking to the other issues up here, because I'm considering to close the current issue for a fresh, follow-up one, then referencing this one.)
In the proposed framework (to be introduced in the upcoming issue thread), there'd be themed styles provided by the system (aka "Themes"), themed styles provided by the app (aka "Skins") and non-themed styles.
Themed resources then can only be addressed by using ThemeResource
, non-themed resouces only by StaticResouce
.
Themed resources would be defined similar to this pattern:
<ResourceDictionary>
<ThemeFacet x:Key="MyApplicationPageBackgroundThemeBrush" FacetType="SolidColorBrush" Default="LightCyan">
<ThemeFacet.Dark Value="MidnightBlue" />
<ThemeFacet.HighContrast Value="Black" />
</ThemeFacet>
<ThemeFacet x:Key="MyMargin" FacetType="x.Int32" Default="7" HighContrast="10"/>
<!-- usage of a themed resource: -->
<Style TargetType="Page">
<Setter Property="Background" Value="{ThemeResource MyApplicationPageBackgroundThemeBrush}"/>
</Style>
</ResourceDictionary>
The color naming system and inheritance would be improved in the suggested revamp, too (see above issues).
Your thoughts?
What would happen if a library (such as WinUI 2) expects a resource to be a themeresource, but the developer has decided to make it a non theme resource? Or what about something that a library thinks is a static resources, but the developer decides to have a different value for the resource based on theme? Would the library/reference break in that case as there would be a mismatch between "Reference this as type X resource" and "The resource is of type Y"? Or would the framework try to go up the tree and find the next resource with that name and that type, so if you reference a theme resource, it will keep looking for a resource with that name that is a theme resource and skip over any resources with the same name that are not defined in themes? This skipping behavior could of course get quite costly.
Would you mind elaborating on a particular case of your concern? Is it about ...
I tried, but I don't seem to be able to follow you. I cannot come up with a situation where issues may be introduced. Perhaps I'm missing something.
To better tell the existing idea of a Style
from the suggested ThemedStyle
I renamed my suggestion above to ThemeFacet
. The suggested Facet is supposed to serve as an intermediate layer between styles and resources.
A ThemeFacet
is kind of a StaticFacet
with more than one single value; similar to this:
internal class __FacetBase
{
public string Key;
public Type FacetType;
}
public class StaticFacet : __FacetBase
{
public object Value;
public StaticFacet() {}
public StaticFacet(object resource)
{
switch (resource)
{
case ThemeFacet tFacet
throw new ArgumentException("Invalid assignment.");
break;
case StaticFacet sFacet
Value = sFacet.Value
break;
default:
Value = resource;
break;
}
}
}
public class ThemeFacet : __FacetBase
{
private enum Theme { Default, Light, Dark, HighContrast };
private object?[] _values = new object?[Theme.GetValues().Length];
public object Default { get => _values[Theme.Default] ?? throw InvalidOperationException("Default facet not defined"); set => _values[Theme.Default] = value; }
public object? Light { get => _values[Theme.Light]; set => _values[Theme.Light] = value; }
public object? Dark { get => _values[Theme.Dark]; set => _values[Theme.Dark] = value; }
public object? HighContrast { get => _values[Theme.HighContrast]; set => _values[Theme.HighContrast] = value; }
public ThemeFacet() {}
public StaticFacet(object resource)
{
switch (resource)
{
case ThemeFacet tFacet
for (int i = _values.length - 1; i >= 0; --i) _values[i] = tFacet._values[i];
break;
case StaticFacet sFacet
Default = sFacet.Value
break;
default:
Default = resource;
break;
}
}
public object GetObject() => GetObject(GetCurrentThemeName());
public object GetObject(string theme)
{
return Enum.TryParse(typeof(Theme), theme, true, out Theme index)
? _values[index] ?? _values[Theme.Default];
: throw ArgumentException("Invalid theme.");
}
}
(NB: I comprehend that the above are COM interfaces in the real world. I used C# and an inheritance scheme for brevity here.)
A StaticResource
is supposed to only be able to reference StaticFacet
s. Any resource that's referencing a ThemeResource
automatically elevates to become a ThemeFacet
itself. That's recursively supposed to be true:
<Page>
<ResourceDictionary>
<ThemeFacet x:Key="MyMargin" FacetType="x:Int32" Default="7" HighContrast="10"/>
<Style x:Key="MyTextBlockStyle" TargetType="TextBlock" BasedOn="{StaticResource TitleTextBlockStyle}">
<Setter Property="Margin" Value="{ThemeResource MyMargin}" />
</Style>
</ResourceDictionary>
<StackPanel>
<!-- The following two references should result in compile time errors:
<Border Margin="{StaticResource MyMargin}">
<TextBlock Style="{StaticResource MyTextBlockStyle}" >Test</TextBlock>
</Border>
-->
<Border Margin="{ThemeResource MyMargin}">
<TextBlock Style="{ThemeResource MyTextBlockStyle}" >Test</TextBlock>
</Border>
</StackPanel>
</Page>
When compiling, the compiler converts the Style
element in the above example into:
<ThemeFacet x:Key="MyTextBlockStyle" FacetType="Style">
<ThemeFacet.Default>
<Style x:Key="MyTextBlockStyle" TargetType="TextBlock" BasedOn="{StaticResource TitleTextBlockStyle}">
<Setter Property="Margin" Value="{StaticResource MyMargin.Default}" />
</Style>
</ThemeFacet.Default>
<ThemeFacet.HighContrast>
<Style x:Key="MyTextBlockStyle" TargetType="TextBlock" BasedOn="{StaticResource TitleTextBlockStyle}">
<Setter Property="Margin" Value="{StaticResource MyMargin.HighContrast}" />
</Style>
</ThemeFacet.HighContrast>
</ThemeFacet>
MyMargin.Default
/MyMargin.HighContrast
not being ThemeFacet
s themselves, the compiler may optimize their reference to be StaticResource
.Since it is probably easier, I will take your example and adjust it to illustrate the problem I see.
Take the following XAML:
<!-- Somewhere in a library, for example WinUI 2 or WCT -->
<ResourceDictionary>
<StaticFacet x:Key="MyMargin" FacetType="x:Int32" Value="10"/>
<Style x:Key="MyTextBlockStyle" TargetType="TextBlock" BasedOn="{StaticResource TitleTextBlockStyle}">
<Setter Property="Margin" Value="{StaticResource MyMargin}" />
</Style>
</ResourceDictionary>
<!-- In my app referencing said library -->
<Page>
<StackPanel>
<Border Margin="{StaticResource MyMargin}">
<TextBlock Style="{StaticResource MyTextBlockStyle}" >Test</TextBlock>
</Border>
</StackPanel>
</Page>
Now the example above should compile, everything is a staticresource and is referenced as such. But what happens if I decide to override the resource MyMargin
like in the example below:
<!-- In my app referencing said library -->
<Page>
<Page.Resource>
<ResourceDictionary>
<ThemeFacet x:Key="MyMargin" FacetType="x:Int32" Default="7" HighContrast="10"/>
</ResourceDictionary>
</Page.Resource>
<StackPanel>
<!-- The border reference should break since it is trying to reference a themefacet as static -->
<Border Margin="{StaticResource MyMargin}">
<!-- Will this now crash too since the style defined somewhere in a library
expected to reference a staticresource but now it is a themeresource? -->
<TextBlock Style="{StaticResource MyTextBlockStyle}" >Test</TextBlock>
</Border>
</StackPanel>
</Page>
Hope that helps.
Ah, I see.
Yes, it'll break, right as you'd have expected:
That's because in the latter example, you've deliberately chosen to create a new resource, a local page resource, that's overriding any external resource. So, each of the style references later on the same page now references your local resource rather than the external library's resource.
This would be the suggested search direction:
Isn't that the same style resolving algorithm that's already in place now?
Isn't that the same style resolving algorithm that's already in place now?
Yes it is. However with the current styling system, I wouldn't get a compiler error because of that and would still be able to use the styles. I don't think that that kind of overriding should result in compiler errors as it makes lightweight styling more unpredictable and tedious to use. So in order to prevent those errors to happen, every library would need theme resource referencing everywhere to just guard against that possible error which kind of defeats the point.
I would say a warning is good, a compiler error however could result in a lot of frustration because of the aforementioned reason and the fact that that would be a major breaking change resulting in a lot of existing XAML code having to be revisited and checked.
a compiler error however could result in a lot of frustration
How can a compiler error in the case you've described lead to confusion? In the code itself, a local ThemeResource
has been created and that's what's being addressed. I don't see the confusion here.
It's just like defining a certain type in <DataTemplate x:DataType="models:Title">
and then using a invalid model member in Text="{x:Bind Id}"
(or Text="{Binding Id}"
). That'll lead to a compiler error, too. I suppose, no-one would claim this to lead to confusion.
it makes lightweight styling more unpredictable and tedious to use
On the contrary. It's one step to make lightweight styling become more predictable. As this issue demonstrates, the current behaviour is rather unpredictable.
Quote from the Microsoft documentation on lightweight styling:
Overriding the system brushes is generally done at the App or Page level, and in either case the color override will affect all controls that reference that brush β and in XAML many controls can reference the same system brush.
Placing these brush overrides at the App.Resources level, will alter all the buttons within the entire app, instead of on a single page.
I would say a warning is good, a compiler error however could result in a lot of frustration because of the aforementioned reason and the fact that that would be a major breaking change resulting in a lot of existing XAML code having to be revisited and checked.
Sure, this path forward would be alright. The warning could be converted to a compiler error two Windows Runtime editions later. With every improvement decision there's always some loss of old habits adhered to it.
The current style system has a number of quirks (<Style TargetType="TextBlock">
not being applied to components within a DataTemplate
, for instance). The proposal described here is only supposed to remedy one of them.
It should not be a goal to claim: "yeah, styling in Windows Runtime today is much more, well, art than science, but that's the way it is."
How can a compiler error in the case you've described lead to confusion? In the code itself, a ThemeResource has been created and addressed. I don't see the confusion here.
That assumes that you actually have the source code of the styles. Sure, you can dig them up, but you are heavily relying on the fact that the compiler gives a reasonable response, which is not often the case looking at errors like this and this. Those error messages are also because of the fact that parsing and processing markup is not the easiest task.
Another thing you need to account for is what happens at runtime. What happens if I replace a theme resource with a staticresource later? So you would need to also have some runtime check in place to deal with that and throw an exception.
On the contrary. It's one step to make lightweight styling become more predictable. As this issue demonstrates, the current behaviour is rather unpredictable.
I wouldn't say it is unpredictable (and I hope I am not the only thinking it's pretty predictable). The issue you linked is also not really related how theme resource or static resource lookup compare and wouldn't be fixed by this proposal from what I can tell. One of the issues you encountered was related to TextBlock not having an editable template, themeresource/staticresource bindings don't really make a difference at all in that case.
Sure, this path forward would be alright. The warning could be converted to a compiler error two Windows Runtime editions later. With every improvement decision there's always some loss of old habits adhered to it.
Given that the Windows platform has always been backwards compatible and is very sensitive to introducing breaking changes, I would argue that this might not happen in the next two or more winrt editions.
I also wish a few changes would be made but often they are not being done because of legacy software or because it was the norm 10 years ago. Great example is the fact that apps still can request to not be closed to save state (a proposal which you are strongly for iirc) though it is not the best user experience in a lot of cases and apps should be able to deal with sudden shutdowns, A lot of apps (for example office) are already able to recover from a sudden crash.
How can a compiler error in the case you've described lead to confusion? In the code itself, a ThemeResource has been created and addressed. I don't see the confusion here.
That assumes that you actually have the source code of the styles. Sure, you can dig them up, but you are heavily relying on the fact that the compiler gives a reasonable response, which is not often the case looking at errors like this and this. Those error messages are also because of the fact that parsing and processing markup is not the easiest task.
There is already strong IntelliSense support for data binding (see my previous comment). Plus, there's already strong IntelliSense support for referencing resources. It should be a snap to have Visual Studio filter the list of items presented by IntelliSense after typing StaticResource
or ThemeResource
according to facet type.
The same is true for reporting errors in Visual Studio. It should be easy to check if the correct type of facet has been referenced in XAML, or even in code, once the two new types of resource references would have been introduced.
The heart of this proposal is to (internally and explicitly, resp.) wrap every kind of resource into either a StaticFacet
or a ThemeFacet
. So, there will only be a StaticFacet
or a ThemeFacet
that may be referenced by StaticResource
and ThemeResource
, resp.
BTW: A distinction between MergedDictionaries
and ThemeDictionaries
would become redundant when StaticFacet
and ThemeFacet
were introduced.
Another thing you need to account for is what happens at runtime. What happens if I replace a theme resource with a staticresource later? So you would need to also have some runtime check in place to deal with that and throw an exception.
Yes, sure. Given that the current resource referencing system would be getting revamped to wrap any resource by either ThemeFacet
or StaticFacet
, assigning the wrong type of resource at runtime would result in the same kind of error that currently would be thrown when assigning a GridView
object to a Brush
property. I don't see a semantic difference here.
Actually, at runtime a StaticFacet
may be "converted" to become a ThemeFacet
easily, anytime. (I updated my previous message by adding corresponding constructors to StaticFacet
/ThemeFacet
)
Given that the Windows platform has always been backwards compatible and is very sensitive to introducing breaking changes, I would argue that this might not happen in the next two or more winrt editions.
Sure.
During the last few weeks I did a personal research on the public demand for UWP apps based on Windows Runtime (= UWP in the following).
I've been visiting a number of job portals, searching for projects requesting UWP knowledge. The result of my - unrepresentative - research was that I didn't see an overwhelming demand for UWP knowledge. In fact, I couldn't find a single project requesting UWP knowledge.
My - purely personal - conclusion from this (and from studying the UWP documentation) is that lack of demand may be based on the fact the UWP is not a such well designed infrastructure it likes to be. UWP philosophy focusses too much on Windows Mobile - an OS which doesn't even exist anymore. Many of its constructs are clumsy, verbose1, 2, obscure3, sluggish and unsafe4.
To my today's expertise, UWP appears to be a significant risk factor to professional project budget. I believe MS would be well-advised to revamp quite a bit in UWP (if they decide to follow-up on that technology).
My proposal on introducing StaticFacet
/ThemeFacet
here to get UWP apps becoming more reliable is just a small, single step up on that ladder.
Actually, I would like to wrap up on this issue now ...
From your - a contributor's - perspective, would you suggest me to create a new issue for this or do you believe it's sufficient to just stick with this current issue here?
We've been (excellently) discussing so many good and various aspects of this issue now. (Let me stress that I personally feel that you have been a very valuable and constructive discussion partner π. Thank you for taking so much of your valuable time to follow-up here.) - I feel it would be hard to wrap all aspects of this issue in a new issue without creating new ambiguity. So, I'd rather want to stick with this current issue.
Wrapped up in a single sentence, my proposal here is to ...
StaticFacet
/ThemeFacet
to reliably assign themed resources to components in an UWP app.The heart of this proposal is to (internally) wrap every kind of resource into either a StaticFacet or a ThemeFacet. So, there will only be a StaticFacet or a ThemeFacet that may be referenced by StaticResource and ThemeResource, resp.
Right I see. You might actually be able to create custom resource dictionaries and types yourself so you don't have to rely on the framework implementing this since this proposal will definitely take some time if it gets accepted.
Yes, sure. Given that the current resource referencing system would be getting revamped to wrap any resource by either ThemeFacet or StaticFacet, assigning the wrong type of resource at runtime would result in the same kind of error that currently would be thrown when assigning a GridView object to a Brush property. I don't see a semantic difference here.
Ok, if we want to limit what reference type can reference, that behavior makes sense.
Actually, at runtime a StaticFacet may be "converted" to become a ThemeFacet easily, anytime. (I updated my previous message by adding corresponding constructors to StaticFacet/ThemeFacet)
I am not sure how good of an idea that would be given that that would require a themeresource reference to exist for said resource. If that resource is referenced as StaticResource, by (current) definition the resource referenced is evaluated at compile time, updating the resource later doesn't make a difference here. But switching out resources might be a corner case.
From your - a contributor's - perspective, would you suggest me to create a new issue for this or do you believe it's sufficient to just stick with this current issue here?
I would update the description of this proposal since we both already put a lot of thoughts into this that might be relevant for further discussions.
We've been (excellently) discussing so many good and various aspects of this issue now. (Let me stress that I personally feel that you have been a very valuable and constructive discussion partner π. Thank you for taking so much of your valuable time to follow-up here.)
Likewise, I appreciate you taking the time getting back, responding and updating the proposal. I think it was a very good and fruitful discussion!
Actually, at runtime a StaticFacet may be "converted" to become a ThemeFacet easily, anytime. (I updated my previous message by adding corresponding constructors to StaticFacet/ThemeFacet)
I am not sure how good of an idea that would be given that that would require a themeresource reference to exist for said resource.
Ah, yeah, right. I think I got carried away :blush:
If StaticFacet
and ThemeFacet
were introduced, the current differenciation between static and theme resources may be dropped. I.e. no StaticResource
vs. ThemeResource
, and no MergedDictionaries
vs. ThemeDictionaries
.
It just would become generic Resource
and Dictionaries
properties, resp. The facet type itself would define whether a resource was themed. So, referencing automatically determines the type of reference.
If runtime code would replace a StaticFacet
by a ThemeFacet
somewhere in the app's resource reference chain, WinRT should be able to update the corresponding current page references, either automatically or manually triggered.
As the leafs of all resource references would result in being of StaticFacet
type, at runtime WinRT could run an optimization step to replace all upstream references of a page's references with the current theme's final leaf object. So, if there'd be two objects having the same Resource
reference applied, only the first reference would walk up the reference tree, while the second could use the resulting leaf object right away.
I find great interest at anyone who can propose making changes at a core level to make the platform more stable, reliable, and easier to implement and use.
As someone on the design side, I would just like to ask @chingucoding how any changes to styling and theming would work with compared to the current Xaml way, compared to something like CSS?
As someone on the design side, I would just like to ask @chingucoding how any changes to styling and theming would work with compared to the current Xaml way, compared to something like CSS?
I am not sure if I understand your question correctly, are you asking how XAML theming is different to CSS theming from a designer standpoint? The answer to this depends on how involved the designer is in the actual implementation, e.g. if the designer is only involved in creating mockups and leaving the rest to developers or if they are also involved in the actual coding so to speak.
As someone on the design side, I would just like to ask @chingucoding how any changes to styling and theming would work with compared to the current Xaml way, compared to something like CSS?
I am not sure if I understand your question correctly, are you asking how XAML theming is different to CSS theming from a designer standpoint? The answer to this depends on how involved the designer is in the actual implementation, e.g. if the designer is only involved in creating mockups and leaving the rest to developers or if they are also involved in the actual coding so to speak.
I am wondering how this proposal would change XAML styling. Does it move things closer to CSS which is a well known standard, or does it move XAML further away?
Good quesion, @mdtauk!
I suppose it's moving things closer to CSS. Actually, when I was hitting edges in UWP styling so far I always thought to myself: "Why isn't referencing rather like cascading in CSS."
I originally was expecting <Style TargetType="">
to be similar to Type Selectors in CSS, <Style x:Key="">
to be similar to Class Selectors in CSS. And that's actually what I'm striving for to propose to have UWP behave similar to this.
The next thing I'd like to propose to have <Style TargetType="">
work in such a way to solve issues described in the two repositories mentioned in this issue,
Good quesion, @mdtauk!
I suppose it's moving things closer to CSS. Actually, when I was hitting edges in UWP styling so far I always thought to myself: "Why isn't referencing rather like cascading in CSS."
I originally was expecting
<Style TargetType="">
to be similar to Type Selectors in CSS,<Style x:Key="">
to be similar to Class Selectors in CSS. And that's actually what I'm striving for to propose to have UWP behave similar to this.The next thing I'd like to propose to have
<Style TargetType="">
work in such a way to solve issues described in the two repositories mentioned in this issue,
Thank you for the clarification. The code snippits you shared seem quite sensible, and thankfully not too verbose.
I know the WinUI design teams are planning to move the workings into using Design Tokens, and there is a pipeline being developed to output XAML or CSS etc from a single design source (a plugin for Figma)
I wonder if there is some synchronisation that could happen regarding Themes and Inheritance. I will ping some of those involved to bring it to their attention. @chigy @anawishnoff @YuliKl
Proposal: Drop ThemeResource functionality
Summary
Currently, when referencing theme colors, UWP comes with two different flavors of resource references:
StaticResource
ThemeResource
... with
ThemeResource
being the one that's reacting to user session theme changes.I suggest to drop
ThemeResource
and to simply redraw an open application's app window when the user changes his/her user session theme, forcing anyStaticResource
to draw its appropriate theme value accordingly anyway.Additionally, the
Page
class may come with a newSessionThemeChanged
event, so color caches created in app code may be invalidated and repopulated.Rationale
Currently, it's the responsibility of the app programmer to choose
ThemeResource
overStaticResource
to have app theme color references change a component's color. This puts additional burdon to programming an UWP app.I believe this is unnecessary, because when a user changes his/her user session theme, any colors referencing a theme color MUST be changed, regardless of the programmer's choice.
So, it doesn't make sense to differenciate between theme color references that follow a user's demand and theme color references that don't. (The Photo Viewer app, for instance, apparently lacks to utilize
ThemeResource
- It doesn't adhere to user session theme changes. I tend to believe that this is not a feature but rather a programming flaw.)There are only two situations when a user session theme changes colors:
It's when the user takes action to change the user session theme. So, when this happens (usually less than "once in a while"), the most easy implementation would be to just have Windows Runtime invalidate the app window's client area and have the app redraw itself.
When Microsoft Windows Themes are enabled, the theme changes every couple of minutes. When this happens, the app window's system are is invalidated and repainted. When this happens, the client area is invalided, too.
Currently, this results in a noticable stutter. The system has to (a) search for
ThemeResource
references first and then (b) to redraw the application anyway. I believe that step (a) is an unnecessary step, just wasting time.Benefits
ThemeResource
when they are referencing theme colors.