microsoft-ui-xaml
microsoft-ui-xaml copied to clipboard
An Iconic Disaster
WinUI has delivered innovative and impressive new GUI elements, designs, and techniques, and the WinUI team has implemented many clever improvements. But of course, nobody is capable of 100% pure perfection, so some deficiences must exist in WinUI. So now I'd like to talk about a glaring exception in the impressive track record of WinUI; an area desperately in need of improvement: Icon rendering in WinUI hardly works -- it's a disaster currently.
Icons are a very important topic, considering that most apps uses multiple icons in multiple places in multiple kinds of GUI elements (icons in buttons, toolbars, menus, tabs, standalone, etc). Thus it's really surprising to observe that, currently, icon rendering hardly works in WinUI/UWP unfortunately. Considering the extreme ubiquity of icons in apps, I consider this to be a high priority topic.
Use a PNG image as an icon?
For starters, look at a really simple case where you have an instance of Windows.UI.Xaml.Media.Imaging.BitmapImage that was produced from a PNG, and you want to use this PNG BitmapImage as an icon. This should be super simple, right? But no, unfortunately neither Windows.UI.Xaml.Controls.BitmapIconSource nor Windows.UI.Xaml.Controls.BitmapIcon support the ability to render a specified instance of BitmapImage -- surprising but true.
To use your BitmapImage instance as an icon, you are forced to use Windows.UI.Xaml.Controls.Image to render it because BitmapIconSource cannot. This means that, in combination with the other problems I will describe, Windows.UI.Xaml.Controls.IconSourceElement is a nice idea but so badly broken that it's practically unusable currently.
See also: Proposal: Create IconSource from Bitmap stream #601
Use an SVG image as an icon?
For example, you have an SVG image file that you want to use as an icon in multiple places in your app. You're out of luck because the SVG renderer contains bugs. See the most recent messages in this issue:
SVG Image sources behave unpredictably. #825
The names of BitmapIconSource and BitmapIcon suggest that they will not render SVG images because SVG images are vector not bitmap. I haven't actually tested what happens if you try to set BitmapIconSource.UriSource to the URI of an SVG instead of a bitmap. Unfortunately an IconSource subclass named ImageIconSource does not exist currently.
I am surprised to observe that WinUI does not yet have good support for scalable vector icons, neither colored vector icons (such as SVG) nor monochrome vector icons/symbols (such as paths).
SymbolIconSource and SymbolIcon are often unusable
For example, imagine you want to create a button that looks similar to this:

Thus you write XAML like this:
<Button Margin="20">
<StackPanel Orientation="Vertical">
<IconSourceElement Width="64" Height="64" Margin="8">
<IconSourceElement.IconSource>
<SymbolIconSource Symbol="Refresh"/>
</IconSourceElement.IconSource>
</IconSourceElement>
<TextBlock Text="Reload Data" FontSize="20" FontWeight="SemiBold"/>
</StackPanel>
</Button>
But it fails because the above XAML renders as follows:

As you can see, regardless of how large or small you make your IconSourceElement, the symbol still renders at a constant size of 20! Yes, a constant size! I could hardly believe it. Shockingly, SymbolIconSource and SymbolIcon don't scale, and don't provide any way to manually configure the size of the icon, and don't have a FontSize property either. (A FontSize property wouldn't be the right solution but anyway it doesn't exist.)
Following is an awkward inconvenient inefficient workaround that uses a Viewbox element to hack the icon into scaling. An alternative workaround is to view SymbolIconSource as unusable, and stop using it entirely, and instead use a TextBlock element and set its TextBlock.FontSize property.
<Button Margin="20">
<StackPanel Orientation="Vertical">
<Viewbox Width="64" Height="64" Margin="8">
<IconSourceElement>
<IconSourceElement.IconSource>
<SymbolIconSource Symbol="Refresh"/>
</IconSourceElement.IconSource>
</IconSourceElement>
</Viewbox>
<TextBlock Text="Reload Data" FontSize="20" FontWeight="SemiBold"/>
</StackPanel>
</Button>
How IconSourceElement with SymbolIconSource should behave: The same as BitmapIconSource and Windows.UI.Xaml.Controls.Image -- both of those scale the icon/image whereas SymbolIconSource does not -- a strange inconsistency. The icon should be scaled in the same manner as an Windows.UI.Xaml.Controls.Image element does with its default setting of Stretch="Uniform", or the same as a Windows.UI.Xaml.Shapes.Path element with Stretch set to Uniform.
FontIconSource and FontIcon are also broken
FontIconSource and FontIcon are slightly less broken than SymbolIconSource because they have a FontSize property. Actually a FontSize property is a bad solution but at least there exists some way of changing the icon size, and a bad way of changing the icon size is better (less bad) than the nothing that SymbolIconSource provides.
The idea of applying a FontSize to an icon is strange and doesn't make sense. What makes sense is applying a Width and Height to an icon or image or path, not a FontSize. A FontSize property is applicable to text but an icon is not text, rather an icon is akin to an image or path.
Instead of trying to apply font size to an icon, SymbolIconSource and FontIconSource should scale the icon in the same manner as BitmapIconSource does.
SymbolIconSource handles white space better than FontIconSource. For example, have a look at how this SymbolIconSource snippet renders:

<Border Padding="0" HorizontalAlignment="Left" VerticalAlignment="Top" BorderBrush="CadetBlue" BorderThickness="2">
<IconSourceElement Margin="0">
<IconSourceElement.IconSource>
<SymbolIconSource Symbol="Refresh"/>
</IconSourceElement.IconSource>
</IconSourceElement>
</Border>
The above rendering makes sense. The Border encloses the icon without padding. Now compare it with the failure of FontIconSource and FontIcon:

<Border Padding="0" HorizontalAlignment="Left" VerticalAlignment="Top" BorderBrush="CadetBlue" BorderThickness="2">
<IconSourceElement Margin="0">
<IconSourceElement.IconSource>
<FontIconSource Glyph="↻" FontFamily="Global User Interface" />
</IconSourceElement.IconSource>
</IconSourceElement>
</Border>
As you can see above, FontIconSource and FontIcon render with padding/whitespace around the icon. In practice, this makes it difficult to use the icon in a button because the spacing/layout looks strange because of the uncontrollable extra space introduced by FontIconSource. The amount of white space on the left, top, right, and bottom sides varies depending on the font -- the white space comes from the font.
If you have several IconSourceElement instances, such as 10 different buttons (in a row) with icons, and some of those IconSourceElement instances use SymbolIconSource and some use FontIconSource and some use PathIconSource, then the 10 buttons look strange and inconsistent with each other because some have extra whitespace/padding (those that use FontIconSource) while the others don't.
FontIconSource and FontIcon are not any better than using a TextBlock element. They render the same as TextBlock. This rendering behavior makes no sense because they are supposed to render as icons not text.
If you use TextBlock instead of FontIcon, you might try to use the OpticalMarginAlignment property to eliminate the problematic whitespace/padding, but it doesn't work, as you can see following. The first image (left) is with OpticalMarginAlignment="None" and the second image (right) is with OpticalMarginAlignment="TrimSideBearings". As you can see, TrimSideBearings didn't trim anything at all, rather it moved the space on the left side to the right side (the total width remains unchanged), and it didn't trim the top and bottom sides, and no other trimming option exists in OpticalMarginAlignment.

<StackPanel Orientation="Horizontal">
<Border Margin="5" Padding="0" HorizontalAlignment="Left" VerticalAlignment="Top" BorderBrush="CadetBlue" BorderThickness="2">
<TextBlock Text="⎈" FontFamily="Global User Interface" FontSize="100" OpticalMarginAlignment="None" Margin="0" Padding="0"/>
</Border>
<Border Margin="5" Padding="0" HorizontalAlignment="Left" VerticalAlignment="Top" BorderBrush="CadetBlue" BorderThickness="2">
<TextBlock Text="⎈" FontFamily="Global User Interface" FontSize="100" OpticalMarginAlignment="TrimSideBearings" Margin="0" Padding="0"/>
</Border>
</StackPanel>
In WPF, one way of rendering a glyph/character as an icon (without whitespace/padding) is to do this:
- Use either
System.Windows.Media.FormattedText.BuildGeometryorSystem.Windows.Media.GlyphRun.BuildGeometryto convert the glyph/character to aGeometryinstance. - Create an instance of
System.Windows.Shapes.Pathand set thePath.Dataproperty to theGeometryreturned byBuildGeometry. - Set the
Path.Stretchproperty toUniform.
Sadly, this technique cannot be used in WinUI because an equivalent of FormattedText.BuildGeometry does not exist in WinUI (or not that I'm aware of).
PathIconSource and PathIcon are unusable
For example, you have an instance of Windows.UI.Xaml.Media.PathGeometry that you want to use as a monochrome vector icon in multiple buttons, pages, or places in your app. This should be super simple, right? Just use Windows.UI.Xaml.Controls.PathIconSource or Windows.UI.Xaml.Controls.PathIcon and give it whatever PathGeometry instance you want? But no, unfortunately this fails to render. Surprising but true.
Following you can see the success of Windows.UI.Xaml.Shapes.Path versus the failure of Windows.UI.Xaml.Controls.PathIconSource (or PathIcon), when rendering the same PathGeometry (a house symbol). The first image (left) is the Path element -- it works. The second image (right) is PathIconSource -- a failed (truncated) rendering of an icon.

<StackPanel Orientation="Horizontal">
<Border Margin="5" Padding="0" HorizontalAlignment="Left" VerticalAlignment="Top" BorderBrush="CadetBlue" BorderThickness="2">
<Path Width="90" Height="90" Stretch="Uniform" Fill="Black">
<Path.Data>
M81.799,0 L163.599,75.636001 146.368,75.636001 146.368,136.341 17.229999,136.341 17.229999,75.636001 0,75.636001 23.987998,53.455336 23.987998,16.938999 53.620998,16.938999 53.620998,26.054981 z
</Path.Data>
</Path>
</Border>
<Border Margin="5" Padding="0" HorizontalAlignment="Left" VerticalAlignment="Top" BorderBrush="CadetBlue" BorderThickness="2">
<IconSourceElement Width="90" Height="90">
<IconSourceElement.IconSource>
<PathIconSource>
<PathIconSource.Data>
M81.799,0 L163.599,75.636001 146.368,75.636001 146.368,136.341 17.229999,136.341 17.229999,75.636001 0,75.636001 23.987998,53.455336 23.987998,16.938999 53.620998,16.938999 53.620998,26.054981 z
</PathIconSource.Data>
</PathIconSource>
</IconSourceElement.IconSource>
</IconSourceElement>
</Border>
</StackPanel>
The Path element succeeds because I set its Stretch property to Uniform, but this solution does not work for PathIconSource nor PathIcon -- they have no Stretch property. Thus PathIconSource and PathIcon are unusable and you're forced to use the Path element instead, which means that IconSourceElement is a nice idea but so badly broken that it's practically unusable currently.
The fact that PathIconSource and PathIcon don't scale the icon is especially strange when you consider that BitmapIconSource does scale the icon.
A second reason why PathIconSource and PathIcon are broken is that if you try to use the same icon in multiple buttons, pages, or places in your app, it fails (throws an exception). Unfortunately the Path element also suffers from the same failure, but it only fails in WinUI, not in WPF. In WPF, you can "freeze" a Geometry instance and then use it in an unlimited number of places in your app. For more info, see this issue:
PathIconSource claims to support sharing but throws exception (AKA shared Geometry issue) #827
If your PathGeometry instance represents a stroked figure instead of a filled figure, such as a "+" symbol consisting of a horizontal stroked lines over a vertical stroked line, then PathIconSource does not support your PathGeometry. See issue:
PathIcon/PathIconSource should allow stroke to be set as well as fill #1279
Library of icons in app (re ResourceDictionary)
Edited:
I remembered another important part of this issue. When using PathIconSource, obviously every app needs to store a collection of all the icons that the app uses (icons as paths/geometries in the case of PathIconSource). This should be super simple to do because WinUI already supports the excellent ResourceDictionary feature. Therefore, our problem is simply solved by storing the app's icons in a "MyResourceDictionary.xaml" file, right? But no, unfortunately this only works in WPF, whereas it is still broken in WinUI, even after the number of years that have elapsed since the release of UWP/WinUI.
In WPF, you can easily store a collection of icons in your app like this:
<ResourceDictionary xmlns="..." xmlns:x="...">
<PathGeometry x:Key="HouseSymbol">
M81.799,0 L163.599,75.636001 146.368,75.636001 146.368,136.341 17.229999,136.341 17.229999,75.636001 0,75.636001 23.987998,53.455336 23.987998,16.938999 53.620998,16.938999 53.620998,26.054981 z
</PathGeometry>
<PathGeometry x:Key="RefreshSymbol">
...
</PathGeometry>
<PathGeometry x:Key="SettingsSymbol">
...
</PathGeometry>
</ResourceDictionary>
Actually, to be precise, in WPF, it's recommended to optimize the above by simply replacing PathGeometry with the optimized read-only equivalent of PathGeometry that is named StreamGeometry. Easily done:
<StreamGeometry x:Key="HouseSymbol">
M81.799,0 L163.599,75.636001 146.368,75.636001 146.368,136.341 17.229999,136.341 17.229999,75.636001 0,75.636001 23.987998,53.455336 23.987998,16.938999 53.620998,16.938999 53.620998,26.054981 z
</StreamGeometry>
So that works great in WPF, but StreamGeometry is unsupported in WinUI. As for the other class, PathGeometry, it does exist in WinUI but it still produces a compile-time error message when you try to use it (PathGeometry) in a ResourceDictionary XAML file:
Error XLS0503
A value of type 'String' cannot be added to a collection or dictionary of type 'PathFigureCollection'.
This bug could be easily fixed AFAIK, because most of the necessary work is already done, therefore I find it surprising that this bug still hasn't been prioritized after this number of years. I thought it was standard recommended practice to increase the priority of a bugfix when the bug is easy to fix.
AFAIK the PathGeometry bug is easy to fix because the WinUI XAML compiler already compiles the following successfully, therefore most of the work is already done for PathGeometry.
<ResourceDictionary xmlns="..." xmlns:x="...">
<Path x:Key="HousePathElement">
<Path.Data>
M81.799,0 L163.599,75.636001 146.368,75.636001 146.368,136.341 17.229999,136.341 17.229999,75.636001 0,75.636001 23.987998,53.455336 23.987998,16.938999 53.620998,16.938999 53.620998,26.054981 z
</Path.Data>
</Path>
</ResourceDictionary>
Although Path in ResourceDictionary compiles successfully, you should use PathGeometry not Path. Path is derived from Windows.UI.Xaml.FrameworkElement and Windows.UI.Xaml.UIElement, and each FrameworkElement instance is permitted to have only one parent FrameworkElement instance, and this won't change. Thus you cannot (and should not) try to share the same Path instance among multiple different buttons in your app where the same icon needs to be used in multiple places.
Unlike the Path element, PathGeometry and/or StreamGeometry are suitable for being shared/used in multiple places, but as I mentioned in issue #827, it only works in WPF. Currently WinUI malfunctions (throws an exception) when you try to share/use the same PathGeometry or PathIconSource instance in multiple places, even despite the fact that the documentation says that sharing is supported:
"PathIconSource is similar to PathIcon. However, because it is not a FrameworkElement, it can be shared."
Notice how the documentation says "because it is not a FrameworkElement". This is the same reason why the ResourceDictionary should contain PathGeometry not Path. Path derives from FrameworkElement whereas PathGeometry does not.
The conclusion is that WPF (but not yet WinUI) supports the storage of the app's icons in a "MyResourceDictionary.xaml" file. This is very strange when you consider the fact that the only thing stopping WinUI from supporting it is a small easily-fixed bug in the XAML compiler. (Or maybe the bugfix is more difficult to implement than it appears, because maybe some reason exists that I don't know about, but anyway, this bug needs to be fixed.)
Apps definitely need this ability to store their own icons/symbols, instead of being limited to predefined icons from Microsoft. SymbolIconSource is an excellent feature (thanks!) but obviously it's unreasonable to limit apps to using only the predefined icons/symbols in the Windows.UI.Xaml.Controls.Symbol enumeration.
Classes were not updated for IconSource
When the IconSourceElement and IconSource classes was created in WinUI in order to replace the defective IconElement subclasses, unfortunately various other classes were not updated accordingly. They should have been updated at the same time as when IconSource was released. For example, in order to update MenuFlyoutItem, this needed to be done:
- Create a property in
MenuFlyoutItemnamedIconSourceof typeIconSource. - Mark the old property
MenuFlyoutItem.Iconas obsolete by applyingSystem.ObsoleteAttribute. (This old property usesWindows.UI.Xaml.Controls.IconElement.)
public class MenuFlyoutItem : ...
{
public Windows.UI.Xaml.Controls.IconSource IconSource { get; set; }
[System.ObsoleteAttribute("Use IconSource property instead of Icon property.")]
public Windows.UI.Xaml.Controls.IconElement Icon { get; set; }
}
The following have not yet been updated:
Windows.UI.Xaml.Controls.AppBarButton.IconWindows.UI.Xaml.Controls.AppBarToggleButton.IconWindows.UI.Xaml.Controls.MenuFlyoutItem.IconWindows.UI.Xaml.Controls.MenuFlyoutSubItem.IconWindows.UI.Xaml.Controls.NavigationViewItem.IconWindows.UI.Xaml.Controls.Primitives.NavigationViewItemPresenter.IconWindows.UI.Xaml.Controls.SettingsFlyout.IconSource(usesImageSourcenotIconSource)
Already up-to-date:
Windows.UI.Xaml.Controls.SwipeItem.IconSourceWindows.UI.Xaml.Input.XamlUICommand.IconSource
Although the subclasses of IconSource currently render in a broken manner, this will be fixed and IconSource is still a good idea, thus the various other classes need to be updated to support IconSource instead of the old IconElement subclasses.
Conclusion: They're all broken!
Windows.UI.Xaml.Controls.IconSourceElement is a nice idea and its concept makes good sense, but unfortunately all subclasses of IconSource are currently broken:
BitmapIconSourceSymbolIconSourceFontIconSourcePathIconSource
Fixing this iconic disaster should be a high priority because icons are very common in apps. Despite the fact that nearly all apps use icons, icon rendering hardly works in WinUI!
A FontSize property is applicable to text but an icon is not text
In this case it is, that's why it's called FontIcon.
In this case it is, that's why it's called FontIcon.
It's called FontIcon not TextIcon therefore it shouldn't behave like text, but currently it does behave like text and this text-like behavior causes failures. We could interpret (or re-interpret) it as being named "FontIcon/FontIconSource" because the icon comes from a glyph in a font, and don't interpret the name "FontIcon" as meaning that it should behave like text. Thus it shouldn't have a property that controls the size of the text, but it does. It's meant to (or needs to) behave as an icon not text.
In order to control the icon size, wouldn't you prefer to set the Width and Height properties of IconSourceElement or an ancestor element of your choice, rather than trying to control the icon size via FontIcon/FontIconSource.FontSize?
Before you answer, keep in mind that the concept of IconSourceElement is better than its predecessors BitmapIcon, SymbolIcon, FontIcon, PathIcon. The issue is that BitmapIcon etc are fundamentally defective designs because, for example, if you write some XAML for a ControlTemplate, UserControl, or Page etc and your XAML displays an icon by using BitmapIcon, then the icon is locked to being a bitmap -- that's a problem. The icon cannot be later changed to a path-based or font-based icon because your XAML uses BitmapIcon and BitmapIcon only supports bitmap icons.
This problem cannot be solved by simply editing the XAML to change BitmapIcon to PathIcon whenever you want to switch from a bitmap to a path -- this doesn't work because the person who writes the XAML of a ControlTemplate is often a different person than the various people who use it. The solution is to use IconSourceElement instead of BitmapIcon etc, and then the ControlTemplate works for everyone regardless of what kind of icon they want/need to use, and the ControlTemplate XAML doesn't require modification whenever someone simply needs to display a different kind of icon.
Thus IconSourceElement is an excellent concept, but in practice it only succeeds if IconSourceElement.IconSource can be set to any subclass of IconSource (any kind of icon) without breaking the size of the rendered icon. This means that each subclass of IconSource needs to behave consistently in regards to icon size, but currently they behave wildly differently than each other.
Currently, when you use IconSourceElement in the XAML of your ControlTemplate or Page or wherever, you can easily configure your IconSourceElement instance in a way that makes it render perfectly when IconSourceElement.IconSource is set to BitmapIconSource, but then your IconSourceElement instance breaks (renders incorrectly) as soon as IconSourceElement.IconSource is set to FontIconSource, SymbolIconSource, or PathIconSource. This causes IconSourceElement to be practically unusable, or at least it defeats the purpose of IconSourceElement.
In order to make IconSourceElement.IconSource interchangeable with any subclass of IconSource (any kind of icon), each subclass of IconSource needs to render the icon consistently with the same size as BitmapIconSource and Controls.Image do, meaning all subclasses of IconSource need to scale the icon to fit the available space. IconSourceElement breaks when different different subclasses of IconSource use completely different ways of controlling icon size such as FontIconSource.FontSize.
Thus the existence of FontIconSource.FontSize represents a design defect and it should be removed. However, if people still desire the option to use FontIconSource.FontSize, then instead of removing this property entirely, it could be made optional, meaning it could operate like this:
- When
FontIconSource.FontSizeis set toSystem.Double.NaNor defaults to NaN (similar to how the default value ofFrameworkElement.Widthis NaN), then it would render likeBitmapIconSource,Controls.BitmapIcon, andControls.Imagealready do: Scale the icon. This also makes theWidth/Height/MinWidth/MaxHeightproperties usable/settable in eitherIconSourceElementor an ancestor element of your choice. - When
FontIconSource.FontSizeis not NaN, then it would operate the same as it does today: TheFontSizeproperty controls the size of the icon instead of the normal behavior of scaling the icon. This mode might be useful in some circumstances, but the disadvantage of this mode is that it breaks the interchangeability ofIconSourceElement.IconSource.
An analogy with the Image Control
Windows.UI.Xaml.Controls.Image defines these Source and Stretch properties:
public class Image : ...
{
public Windows.UI.Xaml.Media.ImageSource Source { get; set; }
public Windows.UI.Xaml.Media.Stretch Stretch { get; set; }
...
}
The current design of the Image Control works well. Now imagine what would happen if you remove the Stretch property from Image and instead place it in ImageSource.
public class Image
{
public Windows.UI.Xaml.Media.ImageSource Source { get; set; }
...
}
public class ImageSource
{
public Windows.UI.Xaml.Media.Stretch Stretch { get; set; }
...
}
That would be madness, but let's imagine making it even worse by adding settable sizing properties to ImageSource akin to the Width/Height properties that Image contains/inherits from FrameworkElement:
public class FrameworkElement
{
public double Width { get; set; }
public double Height { get; set; }
...
}
public class Image : FrameworkElement
{
public Windows.UI.Xaml.Media.ImageSource Source { get; set; }
...
}
public class ImageSource
{
public Windows.UI.Xaml.Media.Stretch Stretch { get; set; }
public double Width { get; set; }
public double Height { get; set; }
...
}
That would really be madness -- it'd cause chaos! I believe I don't need to explain why this would cause chaos, because everyone already understands and agrees that the Stretch, Width, Height properties need to be located in Image not in ImageSource. That's obvious.
However, despite the fact that everyone knows that placing Stretch, Width, Height in ImageSource would be madness, the current version of WinUI does engage in this madness anyway, but only in the case of IconSource not ImageSource.
I'm not saying that IconSource.Stretch exists (it doesn't exist), rather I mean that in principle IconSource subclasses behave with the same kind of madness as if IconSource.Stretch did exist:
BitmapIconSourcerenders likeWindows.UI.Xaml.Media.Stretch.Uniform.PathIconSourcerenders likeWindows.UI.Xaml.Media.Stretch.None.SymbolIconSourcerenders likeWindows.UI.Xaml.Media.Stretch.Noneplus a constant size of 20.FontIconSourcerenders likeWindows.UI.Xaml.Media.Stretch.Noneplus a size determined byFontIconSource.FontSize. ThisFontSizeproperty is the same madness as ifImageSource.Width/Heightwould exist instead of (or in addition to)Image.Width/Height.
In principle, the current behavior of IconSource subclasses is the same madness and chaos as if the Image.Stretch property would be moved to ImageSource.Stretch. Also in principle, FontIconSource.FontSize is the same chaos as if settable ImageSource.Width/Height properties would exist.
The WinUI team has repeatedly delivered impressive stuff, except for the dysfunctional icon rendering. No big deal; just fix it and become even greater! :smile:
@jevansaks - is this a proposal? It feels more like a discussion that should lead to one or more proposals.
@verelpode you make some really good points - to summarize and ensure I understand what you're saying, it's that:
- IconSource's API structure/behavior is inconsistent with that of similar components, like Image and ImageSource
- Subclassing IconSource to Bitmap/Symbol/Font/PathIconSource all result in different sizing behavior that isn't consistent and renders IconSource rather unusable because of this
- If IconSource's sizing behavior operated in a similar way to how Image and ImageSource work, it would mean that FontIconSource is practically obsolete, because the need to size the icon would be mostly handled by the system or through height/width properties instead of a "FontSize" property.
Is the above summary correct?
Hi @kikisaints, thanks for the quick reply.
IconSource's API structure/behavior is inconsistent with that of similar components, like Image and ImageSource.
Correct.
Subclassing IconSource to Bitmap/Symbol/Font/PathIconSource all result in different sizing behavior that isn't consistent and renders IconSource rather unusable because of this.
Correct.
If IconSource's sizing behavior operated in a similar way to how Image and ImageSource work, it would mean that FontIconSource is practically obsolete, because the need to size the icon would be mostly handled by the system or through height/width properties instead of a "FontSize" property.
There's a typo in that point. The typo can be correct as follows:
"If IconSource's sizing behavior operated in a similar way to how Image and ImageSource work, it would mean that ~~FontIconSource~~ the property FontIconSource.FontSize is practically obsolete, because ...."
The FontIconSource class is a good idea; don't throw it in the garbage bin; just fix its problems and it will become great. The two problems with FontIconSource are:
- The sizing behavior / "FontSize" property as mentioned above.
- The glyph needs to be rendered without the whitespace/padding that currently surrounds the glyph. In other words, the whitespace/padding behavior of
FontIconSourceneeds to be made consistent withSymbolIconSource. (To implement this fix, note that in WPF,BuildGeometryis one way of eliminating the whitespace/padding.)
I also suggest that the following points are important for inclusion in a summary:
- A common requirement is to share or use the same icon in multiple different places in the app, but this fails (throws an exception) despite the documentation saying that
PathIconSourcesupports sharing. - The WinUI XAML compiler fails to compile
PathGeometryinResourceDictionaryXAML files. See details in my next message.
The first or second version of something is hardly ever great, but who cares? What I love about software development is that we can produce a third or fourth version that is great, and erase the mistakes of the first and second versions. The concept of IconSourceElement is solid and if a new version is released, then WinUI's support for icons can definitely become great. Success is not far away! :smile:
Library of icons in app (re ResourceDictionary)
I remembered another important part of this issue. When using PathIconSource, obviously every app needs to store a collection of all the icons that the app uses (icons as paths/geometries in the case of PathIconSource). This should be super simple to do because WinUI already supports the excellent ResourceDictionary feature. Therefore, our problem is simply solved by storing the app's icons in a "MyResourceDictionary.xaml" file, right? But no, unfortunately this only works in WPF, whereas it is still broken in WinUI, even after the number of years that have elapsed since the release of UWP/WinUI.
In WPF, you can easily store a collection of icons in your app like this:
<ResourceDictionary xmlns="..." xmlns:x="...">
<PathGeometry x:Key="HouseSymbol">
M81.799,0 L163.599,75.636001 146.368,75.636001 146.368,136.341 17.229999,136.341 17.229999,75.636001 0,75.636001 23.987998,53.455336 23.987998,16.938999 53.620998,16.938999 53.620998,26.054981 z
</PathGeometry>
<PathGeometry x:Key="RefreshSymbol">
...
</PathGeometry>
<PathGeometry x:Key="SettingsSymbol">
...
</PathGeometry>
</ResourceDictionary>
Actually, to be precise, in WPF, it's recommended to optimize the above by simply replacing PathGeometry with the optimized read-only equivalent of PathGeometry that is named StreamGeometry. Easily done:
<StreamGeometry x:Key="HouseSymbol">
M81.799,0 L163.599,75.636001 146.368,75.636001 146.368,136.341 17.229999,136.341 17.229999,75.636001 0,75.636001 23.987998,53.455336 23.987998,16.938999 53.620998,16.938999 53.620998,26.054981 z
</StreamGeometry>
So that works great in WPF, but StreamGeometry is unsupported in WinUI. As for the other class, PathGeometry, it does exist in WinUI but it still produces a compile-time error message when you try to use it (PathGeometry) in a ResourceDictionary XAML file:
Error XLS0503
A value of type 'String' cannot be added to a collection or dictionary of type 'PathFigureCollection'.
This bug could be easily fixed AFAIK, because most of the necessary work is already done, therefore I find it surprising that this bug still hasn't been prioritized after this number of years. I thought it was standard recommended practice to increase the priority of a bugfix when the bug is easy to fix.
AFAIK the PathGeometry bug is easy to fix because the WinUI XAML compiler already compiles the following successfully, therefore most of the work is already done for PathGeometry.
<ResourceDictionary xmlns="..." xmlns:x="...">
<Path x:Key="HousePathElement">
<Path.Data>
M81.799,0 L163.599,75.636001 146.368,75.636001 146.368,136.341 17.229999,136.341 17.229999,75.636001 0,75.636001 23.987998,53.455336 23.987998,16.938999 53.620998,16.938999 53.620998,26.054981 z
</Path.Data>
</Path>
</ResourceDictionary>
Although Path in ResourceDictionary compiles successfully, you should use PathGeometry not Path. Path is derived from Windows.UI.Xaml.FrameworkElement and Windows.UI.Xaml.UIElement, and each FrameworkElement instance is permitted to have only one parent FrameworkElement instance, and this won't change. Thus you cannot (and should not) try to share the same Path instance among multiple different buttons in your app where the same icon needs to be used in multiple places.
Unlike the Path element, PathGeometry and/or StreamGeometry are suitable for being shared/used in multiple places, but as I mentioned in issue #827, it only works in WPF. Currently WinUI malfunctions (throws an exception) when you try to share/use the same PathGeometry or PathIconSource instance in multiple places, even despite the fact that the documentation says that sharing is supported:
"PathIconSource is similar to PathIcon. However, because it is not a FrameworkElement, it can be shared."
Notice how the documentation says "because it is not a FrameworkElement". This is the same reason why the ResourceDictionary should contain PathGeometry not Path. Path derives from FrameworkElement whereas PathGeometry does not.
The conclusion is that WPF (but not yet WinUI) supports the storage of the app's icons in a "MyResourceDictionary.xaml" file. This is very strange when you consider the fact that the only thing stopping WinUI from supporting it is a small easily-fixed bug in the XAML compiler. (Or maybe the bugfix is more difficult to implement than it appears, because maybe some reason exists that I don't know about, but anyway, this bug needs to be fixed.)
Apps definitely need this ability to store their own icons/symbols, instead of being limited to predefined icons from Microsoft. SymbolIconSource is an excellent feature (thanks!) but obviously it's unreasonable to limit apps to using only the predefined icons/symbols in the Windows.UI.Xaml.Controls.Symbol enumeration.
Note my message here is a different issue than https://github.com/microsoft/microsoft-ui-xaml/issues/827 because https://github.com/microsoft/microsoft-ui-xaml/issues/827 describes the sharing failure whereas the main point of my message here is the failure of the XAML Compiler to compile PathGeometry in ResourceDictionary.
Classes were not updated for IconSource
When the IconSourceElement and IconSource classes was created in WinUI in order to replace the defective IconElement subclasses, unfortunately various other classes were not updated accordingly. They should have been updated at the same time as when IconSource was released. For example, in order to update MenuFlyoutItem, this needed to be done:
- Create a property in
MenuFlyoutItemnamedIconSourceof typeIconSource. - Mark the old property
MenuFlyoutItem.Iconas obsolete by applyingSystem.ObsoleteAttribute. (This old property usesWindows.UI.Xaml.Controls.IconElement.)
public class MenuFlyoutItem : ...
{
public Windows.UI.Xaml.Controls.IconSource IconSource { get; set; }
[System.ObsoleteAttribute("Use IconSource property instead of Icon property.")]
public Windows.UI.Xaml.Controls.IconElement Icon { get; set; }
}
The following have not yet been updated:
Windows.UI.Xaml.Controls.AppBarButton.IconWindows.UI.Xaml.Controls.AppBarToggleButton.IconWindows.UI.Xaml.Controls.MenuFlyoutItem.IconWindows.UI.Xaml.Controls.MenuFlyoutSubItem.IconWindows.UI.Xaml.Controls.NavigationViewItem.IconWindows.UI.Xaml.Controls.Primitives.NavigationViewItemPresenter.IconWindows.UI.Xaml.Controls.SettingsFlyout.IconSource(usesImageSourcenotIconSource)
Already up-to-date:
Windows.UI.Xaml.Controls.SwipeItem.IconSourceWindows.UI.Xaml.Input.XamlUICommand.IconSource
Icons in "Visual Assets" in manifest
On the topic of icons, unfortunately I also had a disappointing experience when configuring the icons in the "Visual Assets" tab in the "Package.appxmanifest" of a WinUI UWP app in Visual Studio 2019.
Lack of knowledge of runtime image scaling
The current design of "Visual Assets" represents a surprising lack of knowledge of the commonly-known fact that at runtime an image can be quickly and easily rendered at a smaller or larger size -- scaled to fit any rectangle. This rendering-with-scaling is quick regardless of whether the app is running in a smartphone or desktop computer. When the image is rendered at exactly 50% or 25% size, the scaling is even faster and delivers excellent image quality. Here is a screenshot of the current GUI for "Large Tile":

As you can see above, it recommends that the app developer provide 3 sizes of the same image, plus 2 optional sizes (up to 5 sizes of the same image). Thus it represents lack of knowledge of the fact that only one image file is required for "Large Tile" because the image can be scaled at runtime.
As I mentioned, the quality and speed is especially good when the rendered size is 50% or 25% of original. As you can see in the screenshot above, the 3 recommended sizes are 1240, 620, and 310 and those are multiples of 310. 50% of 1240 is 620, and 25% of 1240 is 310. Thus if only one image is provided, and if that one image is 1240x1240 px, then the 620 and 310 versions can be rendered at runtime with excellent image quality and speed, even better than if they weren't multiples. The current GUI for configuring "Large Tile" (with 5 sizes of the same image) is nonsense.
"Scaling Mode" option makes no sense
This lack of knowledge of image scaling is further evident in the "Scaling Mode" option that provides 2 choices named:
- "Bicubic (Sharper Edges)"
- "Nearest Neighbor (Smoother Edges)"
Both of those descriptions are wrong. For "Nearest Neighbor", it says "Smoother Edges", but Adobe Photoshop says the opposite: "Nearest Neighbor (preserve hard edges)". Visual Studio says the opposite of both Photoshop and Wikipedia. Wikipedia says "Nearest-neighbor ... introduce jaggedness in previously smooth images."
Not only are the descriptions wrong, but Visual Studio's "Scaling Mode" option shouldn't exist at all, because "Nearest Neighbor" never produces a better result than bicubic scaling (for the purpose of Visual Studio). Furthermore, the scaling should be performed at runtime, not in Visual Studio, meaning only one image file should be provided for "Large Tile". Thus the "Scaling Mode" option should be removed from "Visual Assets".
Word wrapping is broken
Another problem is word wrapping. In the section titled "Display Settings", you can enter a name in the textbox "Short name" and you can tick "Show name", but when the tile is displayed in the Start menu, the name fails to wrap onto 2 lines, despite the fact that other Microsoft products somehow do achieve 2 lines. For example, MS Blend displays as:

In your own app, if you set "Display Settings" to "Blend for Visual Studio 2019", then it appears with only one line, truncated:

Nonsense file names
For "Small Tile", the default file name is "SmallTile.png" and that makes sense. Likewise for "Large Tile", the default file name is "LargeTile.png" and again that makes sense. Now what do you think the file name is for "Medium Tile"? A sensible guess would be "MediumTile.png", but no, the name is "Square150x150Logo.png", even when the PNG file is not 150x150 pixels. That's nonsense.
The problem repeats itself for "App Icon". What do you think the file name is for "App Icon"? A sensible guess would be "AppIcon.png", but no, the name is "Square44x44Logo.png", even when the PNG file is not 44x44 pixels. Likewise for "Wide Tile", you'd expect "WideTile.png", but no, the name is "Assets\Wide310x150Logo.png". The file name says "Logo" instead of "Tile", and it says 310x150 even when the PNG file is not 310x150 pixels.
A file named "Wide310x150Logo.scale-200.png" is not 310x150 pixels. It's actually 620 x 300 pixels. The file name includes the text "scale-200" but that's ridiculous, as I explained previously in regards to runtime image scaling and 50% and 25%.
When you click any asset within the "Large Tile" section, such as when you click 620x620 px, a window appears and describes the asset incorrectly. It says the wrong name and wrong size. Instead of saying "Large Tile 620x620", it says "Square 310x310 logo". It says: "This asset is used for the Square 310x310 logo field and is shown in the following location(s)." The underlying XML schema says "Square310x310Logo" but unfortunately that design is nonsense.
Requirement for "Wide Tile" is nonsense
Here is a screenshot of the nonsensical message that appears when you try to delete "Wide Tile":

Reasons why that message is nonsense:
- The words "Square 310x310 logo" are nonsense -- it actually means "Large Tile".
- The logic of the requirement is reversed. Logically speaking, if the Medium and Large Tiles are supplied, then they can also be used to render the Wide Tile by default, by rendering the icon in the center of the Wide Tile. If you have a medium icon, you can use it to render a wide tile, but the message says the opposite: It says if you have an icon, then you must provide another icon. It's nonsense.
- (I do realize that some apps will want or need to supply a Wide Tile image, but it shouldn't be mandatory, and it shouldn't have 5 size of the same image.)
In the "Wide Tile" section, 3 assets are recommended, but nothing should be recommended by default in Wide Tile, and nothing in Wide Tile should be mandatory (regardless of whether "Square 310x310" is supplied). "Wide Tile" can be supported but it's hardly a good recommendation. Except for games, none of the Microsoft apps use the "Wide Tile" visual asset. The Microsoft Weather app does not use it either. Weather supports wide tiles via live tile, NOT via a Visual Asset.
"Medium Tile" is mandatory for no reason
I fully supplied the "App Icon" section of "Visual Assets", and then I tried to delete the unnecessary images in the "Medium Tile" section, and then it displayed the following nonsensical error message:

That error message is nonsense because:
- The words "Square 150x150 logo" are incomprehensible and need to be replaced with a choice of words that people can actually understand, meaning it needs to say "Medium Tile" instead of "Square 150x150 logo". I have a double degree from a respected university but the words "Square 150x150 logo" are still mumbo-jumbo that I could not understand and were forced to decipher.
- The error message does not state any reason for making "Medium Tile" mandatory, because no reason exists, but if something will be made mandatory, then it's necessary to have at least one reason for making it mandatory. In this case, the number of reasons is zero, thus it shouldn't be mandatory.
- The idea of making "Medium Tile" contain a duplicate of the image in "App Icon" makes no sense. There is no need for "Visual Assets" to produce so many duplicates of the same image.
Here is a sensible design: If "Medium Tile" is supplied, then use it. If it's unsupplied, then use the image(s) in "App Icon" to render the "Medium Tile" at runtime, as the default behavior. Visual Studio's default behavior of duplicating the same image in "Medium Tile" and "App Icon" makes no sense. You click the "Generate" button and suddenly you have many unnecessary duplicates of the same image!
Other problems in "Visual Assets"
- The "Visual Assets" GUI fails to provide any way to delete an unwanted asset or scale. You can delete an entire group but not an individual scale.
- When you click the 1240 x 1240 large tile, it displays the image in a window but the window has no scrollbars and the window is so large that the "Close" button is offscreen, despite the fact that my computer has a relatively large monitor attached.
- Too many assets are recommended yet unnecessary and serve no purpose.
- By default, the "Asset Generator" auto-generates images for "App Icon" and tiles, but it strangely also generates an image for the splashscreen, despite the fact that it makes no sense to display an icon as a splashscreen.
- "Apply recommended padding" would be more useful if it allowed the app developer to choose an amount of padding, instead of using the "recommended" amount that doesn't work well for all icons/tiles.
- When you click "Large Tile" on the lefthand side, you expect it to show the settings for "Large Tile", but it also shows some settings that affect "Medium Tile" and "Wide Tile" (the settings in the "Display Settings" section).
On a few occasions in the past, I produced amateurish work, but I'm proud to say that I revisited my work and transformed it from amateurish to professional, and the customers loved receiving the improvements. Everyone produces amateurish work sometimes. The current version of "Visual Assets" is one of these examples of things that need to be transformed from amateurish to professional.
Here is a screenshot of the files that Visual Studio 2019 produces when you auto-generate every image in "Visual Assets". A fair and accurate description of this behavior is: Amateurish. The file list is not long because it's advanced and powerful. In reality, the list is long because it's amateurish work and falls far below the usual high standards of UWP. Many things in UWP are advanced and powerful and wonderful, but "Visual Assets" is not yet one of them.

Microsoft has experienced some difficulties in convincing app developers to develop for Windows Phone instead of (or in addition to) Android and Apple iOS. One factor to keep in mind is the effect of first impressions. First impressions count. When an app developer used other products in the past, and one day uses Visual Studio for the first time, what will his/her first impression be?
The first impression when seeing "Visual Assets" is that Microsoft seems amateurish, and then the app developer begins to wonder: "If Microsoft couldn't even manage to do the app icon/tile, then what's the rest of UWP like? Is the whole thing amateurish?"
In reality, UWP is really great stuff -- UWP is advanced and professional -- but app developers can be misled by the bad first impression of "Visual Assets". What happens next? App developers swallow the amateurish "Visual Assets" and then start writing an app and they try to create some icons inside of their app, and then they discover that WinUI's icon rendering is badly broken, hardly works, and the first impressions deteriorate even further. This is a sad result because in reality many things in WinUI and UWP are wonderful, but the first impressions (icons) can mislead developers into thinking that UWP is low quality.
I struggled with that form too. I was trying to figure out the unplated/plated/light mode/dark mode rules and this form was no help. It is a very unintuitive “tool”.
@moshegutman -- Oh yes, "unplated" is another problem; thanks for reminding me. I can explain "unplated". Surprisingly, the newly-invented term/jargon "unplated icon" means "a normal icon" in the normal sense of the word "icon".
This raises the question: If "unplated icon" just simply means a normal icon, then why not speak normally and just simply say "icon" instead of confusing everyone by inventing a new term that means the same as the preexisting word "icon"?
I can think of two possible answers to this perplexing question. I'm pretty sure that the answer is one of these:
- An honest mistake; or
- The same as the reason why lawyers and judges invented a bunch of legal jargon: Because it sounds impressive and intelligent to use jargon, and it separates "insiders" from "outsiders". In reality, the use of obscure legal jargon (or tax jargon) represents juvenile behavior, but it sounds intelligent and it impresses people, and that's why lawyers, judges, and accountants use it, despite the juvenile and unprofessional nature of such behavior. I wish they would just grow up, but unfortunately it's not going to happen.
In the case of the "unplated" jargon, I think the answer is probably number 1, an honest mistake. In various other cases in life, the answer is number 2.
Yeah, I think it goes back to the windows phone days where the tile background in the start menu is the “plate” that the icon is on. But either way, through Visual Studio it isn’t possible to make all the variations of icons needed for a proper app.
I suspect that the Visual Assets recommendations will be changing with WinUI 3.0 - because of the new icon styles used by Windows 10 X
Here are a few more things that are unfortunately bungled in "Visual Assets".
Firstly, imagine that I wrote an app and in my app there is a place to choose a color for some purpose. However, instead of using something like ColorPicker, I use TextBox and require the user to type in a hexadecimal RGB color. It would be accurate to describe that part of my app as amateurish. As a matter of fact, I really did that once, in a real app, but later I improved it and eliminated my amateurish work. I'd expect the same to be done for "Visual Assets" -- fix it. In the following screenshot, I've circled the part of "Visual Assets" that has the amateurish way of choosing colors:

More is bungled. The following screenshot shows the default setting of "Tile background" -- "transparent". When "Tile background" is "transparent", the tile background is opaque! Yes, in this case, "Visual Assets" uses the word "transparent" to mean "opaque". How can you configure it to be truly transparent? You cannot. It's always opaque. I have no complaint about it being always opaque, but if it's always opaque, then it shouldn't say transparent. "Visual Assets" uses the word "transparent" to mean "non-transparent default tile background color".

@mdtauk wrote:
I suspect that the Visual Assets recommendations will be changing with WinUI 3.0 - because of the new icon styles used by Windows 10 X
I haven't looked at 10X, but do you mean the "Windows Light Theme"? If yes, then this is already in Visual Studio 2019 -- see the icons called "Light Unplated Target" in the "App Icon" section of "Visual Assets".
In the "Asset Generator" section, the option "Apply color conversion for Windows Light Theme" seems to be badly broken, or at least it didn't work with the icons I tested it with. I didn't have time to perform a comprehensive test with many icons, but I did test the main feature that should work: I tested with an icon that has a light gray border meaning it is intended for use on a dark background. This means that for the "Windows Light Theme", the light version of the icon needs the light gray border to be changed to a dark gray border, but "Apply color conversion for Windows Light Theme" completely failed to do this. It did make a modification to the icon, but it was a weird pixelated modification that didn't appear to be even remotely successful.
Not often, but occasionally Microsoft does attempt impossibly difficult tasks -- tasks that are far too difficult to achieve, even for a company as large as Microsoft. My impression of "Apply color conversion for Windows Light Theme" is that it seems to be one of these few cases where Microsoft attempts an impossibly difficult task. Therefore I think that Microsoft shouldn't attempt to repair this option, rather Microsoft should remove it entirely, because Microsoft does not possess sufficient resources to achieve impossibly difficult tasks.
Alternatively, if it won't be removed, then give it a completely different name such that it will no longer be an impossibly difficult task.
I gave this issue the title "An Iconic Disaster" because the current situation for icons really is an iconic disaster. The icon support is terrible currently. But overall UWP and WinUI are excellent. Keep up the good work! :smile:
Unfortunately I still haven't finished the substantial work of documenting the list of defects in "Visual Assets" :frowning_face: In the following screenshot, you can see that I've set "Tile background" to a blue color, and understandably this blue color is displayed in the previews in the sections "Small Tile", "Medium Tile", "Large Tile". That part of it behaves correctly.

"Tile background" behaves incorrectly in the "App Icon" section:

You can see in the above screenshot that the first row is labelled "Scaled Assets" but the other 3 rows are missing their labels -- that's a strange inconsistency. The last 2 rows are the so-called "unplated icons" meaning actually "normal icons" that don't have a plate/tile. Confusingly, Visual Assets uses multiple different words for the same things, thus plate = tile, and unplated = non-tile. As you can see above, the non-tile icons (the last 2 rows) are incorrectly rendered with the blue tile background. Obviously that's a mistake because non-tile icons shouldn't be rendered as tiles, thus the color specified in the "Tile background" textbox shouldn't be rendered under the non-tile ("unplated") icons, but it is.
If you click on any of the unplated icons, it displays a window like the following, and you can see it says the icon is used in Windows Explorer etc, but NOT used as a tile. The "Tile background" color is incorrectly rendered in the preview despite the fact that it isn't a tile.

A few other defects are also visible in the above window, such as the wrong name ("Square 44x44 Logo"), and also the fact that it doesn't say "unplated" in this window despite the fact that I clicked on an icon that did say "unplated".
To summarize, the defects in the "App Icon" section include these:
- The "Tile background" color is incorrectly rendered underneath non-tile ("unplated") icons (the last 2 rows).
- The purpose of each row is only displayed for the first row (the first row is labelled "Scaled Assets" but the other rows are unlabelled). For the remaining 3 rows, the purpose is displayed only in a tooltip when the mouse pauses above one of the previews. That's inconsistent and bad GUI design.
- Lack of knowledge that images can be scaled at runtime. The 176x176 size is ridiculous. The following image sizes should be removed because they should be scaled at runtime from the 256x256 image: 176x176, 88x88, 66x66, 55x55, 48x48, 44x44.
- The 16x16 size is ridiculous and should be removed. We're not living in the 1990's anymore. Nowadays computer and smartphone screen resolutions are much higher than in 1995, thus the tiny 16x16 size is ridiculous considering that 1995 was 25 years ago. As for the 32x32 size, it could be retained (an exception could be made for this small size) because it is so small that runtime scaling may produce an unsatisfactory result (when 256x256 is scaled to 32x32). Re 16x16, the need to render the icon at 16x16 size is unlikely but if it happens, then at runtime the 32x32 icon can be scaled to 16x16.
- When using "Asset Generator" with default/recommended settings (when "Recommended Scales" is ticked), it auto-generates three 16x16 image files. This behavior makes no sense. It's completely illogical. If 16x16 is an auto-generated image, then there is no need to supply it. It's only logical to supply a 16x16 image if it is manually created by a graphic designer person who specially tweaks/adjusts it in order to make its appearance acceptable at such a tiny size.
- It can be justifiable to supply multiple image sizes if they're manually created/tweaked images, whereas it's nonsense if they're auto-generated by "Asset Generator" because if they're auto-generated then they can be scaled at runtime. Back in the 1990's, it was slow to scale an image at runtime, but that was long ago, and nowadays we don't need to pre-generate many sizes of the same image.
- It doesn't provide any way to delete one of the images within the "App Icon" section. For example, it doesn't allow you to click or right-click 44x44 and then click a "Delete" button or command.
- The preview for 256x256 is rendered smaller than the preview for 176x176. That's the reverse of what you'd expect, considering that 256x256 is actually larger than 176x176. Various other previews also exhibit strange sizes.
- The "App Icon" section uses absurd file names such as "Square44x44Logo.targetsize-256.png". The default file name for the "App Icon" section is expected to be "AppIcon.png" like how the "Small Tile" section uses "SmallTile.png". However, "App Icon" uses a nonsensical file name: "Square44x44Logo-XXXXXX.png". The name is especially nonsensical because it generates multiple variations of "Square44x44Logo-XXXXXX.png" (such as "Square44x44Logo.targetsize-256.png") that all say "44x44" despite the fact that most of these PNG files are NOT 44x44 pixels.
- It uses multiple different names for the same things. "Unplated icon" = a normal icon. "Plate" = tile. "Square44x44Logo.png" = "App Icon". And others.
Icons and tiles for an app should be a simple issue. It shouldn't require a PhD to understand it. It shouldn't require hours of deciphering. It shouldn't require the following ridiculous translation table.
| Term | Meaning |
|---|---|
| Asset | Image. |
| Unplated icon | A normal icon in the normal sense of the word "icon". There was no need to invent a confusing new term for normal icons. |
| Plate | The same as tile. A duplicate term for the same thing. |
| Alternate Form (altform) | Normal form. Unplated form. |
| Square 44x44 Logo | App Icon. Although it says 44x44, these images are mostly not 44x44. |
| Square 71x71 Logo | Small Tile. Although it says 71x71, these images are mostly not 71x71. |
| Square 150x150 Logo | Medium Tile. Although it says 150x150, these images are mostly not 150x150. |
| Wide 310x150 Logo | Not logo. Actually means tile, specifically "Wide Tile". Although it says 310x150, these images are mostly not 310x150. |
| Square 310x310 Logo | Large Tile. Although it says 310x310, these images are mostly not 310x310. |
| Lock Screen Logo | Badge Logo. |
| Store Logo | Package Logo. |
| transparent | Non-transparent. It means opaque default tile background color. |
| Bicubic (Sharper Edges) | Softer edges. |
| Nearest Neighbor (Smoother Edges) | Jagged edges. |
| Scale 100 | Does not mean 100%. It actually means an arbitrarily chosen size such as 150x150 pixels. For "Medium Tile", the so-called "Scale 100" means 150x150 pixels but no reason exists to explain why an arbitrary size such as 150x150 pixels should be called "100%". The scaling system of "Visual Assets" is illogical. |
| Scale 400 | The largest image supplied. |
| Scale 200 | An unnecessary useless duplicate of the exact same image as "Scale 400", but scaled to 50% of the image "Scale 400". Serves no real purpose because normally images are scaled at runtime, not prior to compile-time. There is no reason to pre-generate multiple sizes of the same image. |
| Scale 150 | Another unnecessary duplicate that serves no real purpose. |
| Scale 125 | Yet another unnecessary duplicate that serves no real purpose. This image size served a purpose back in the year 1995 because back then it was slow to scale an image at runtime, but that was 25 years ago! Nowadays we don't need to store many duplicates of the same image. |
I'd like to hilite an excellent piece of advice that @codendone mentioned in another issue. Although the other issue was unrelated to icons, this advice is also applicable to icons and many other topics in general. He wrote:
There are a couple challenges which come up: API: How do we keep the API simple yet still support full flexibility so it isn't too limited?
That's an important principle. The current version of "Visual Assets" runs very contrary to this important principle. I don't say that "Visual Assets" should be reduced to only one single PNG file, but it shouldn't be 55 PNG files. Let's not jump to either extreme. Currently it generates/uses up to 55 PNG files -- that's ridiculous. A reasonably balanced solution is needed and 55 images is far away from being reasonably balanced between simplicity and full functionality. The full functionality can be retained with a much simpler design of "Visual Assets".
I've saved the best for last. Here is the number 1 most absurd thing about the current version of "Visual Assets". When you use "Asset Generator" with its "Recommended Scales" setting, and you want to use the full tile area thus you untick "Apply recommended padding" (or tick it if you want), and you give it a source tile image of a reasonable size such as 300x300 or whatever, then as I said it generates many unnecessary smaller duplicates of the same image for no reason, but that's not all it does. Here comes the number 1 most absurd thing: In the "Large Tile" section, it takes the 300 x 300 source image file and scales it UPWARDS to produce a big blurry 1240 x 1240 PNG file that consumes roughly 1 megabyte on average!!
That upwards scaling to 1240 x 1240 is so absurd that if Mac users knew about this, they'd burst out laughing. Scaling it downwards is bad enough, but scaling it upwards is just... so... ridiculous. It's not any exaggeration whatsoever to describe it as absurd. Mac fanatics will say it's hilarious. It's even worse than I said because the 1240 x 1240 PNG file isn't the only one. It's one of multiple upscaled image files. It also scales up the 300x300 source image to produce PNG files of sizes 310x310, 310x150, 620x620, 620x300, 600x600, and 1240x600.
It's still even worse than I said. The default setting also includes scaling up the 300x300 image to produce a 2480 x 1200 splashscreen that also consumes roughly 1 megabyte on average. And a 1240 x 600 splashscreen. Wait, there's one more: It also scales upwards to a 620 x 300 splashscreen.
I do realize that the "Scale 400" image files are supposed to correspond with the setting in Start menu / Settings / Display / "Scale and layout", but this reasoning is completely illogical. It makes no sense whatsoever. 400% doesn't even exist in the ComboBox in "Scale and layout", and even if 400% did exist there, it would still be completely illogical to pre-generate upscaled PNG files.
The behavior of "Visual Assets" is just beyond belief. It's very unusual for Microsoft to publish something of very low quality, but this time it happened unfortunately. "Visual Assets" is extraordinarily low quality software.
Instead of fixing all the resolution problems in @verelpode 's posts on visual assets directly, you could just obviate them by making a large simplification.
- SVG are by far the most important case, as almost all icons are vector graphics. A single svg file should be usable, with no need to generate or display scaled assets.
- To support bitmaps (for backwards compatibility), a single high-res image can be used for each case, and if there is a need to use smaller ones, these can be generated as a release build step. Again there is no need to display scaled assets in the UI. There isn't any need to support manual specification of multiple versions of the same image.
@charlesroddie -- I believe you've described an excellent solution that fits the needs: A modern design with a good balance between power and simplicity. Surely nobody will be able to think of a better plan than what you said.
Additionally, the same plan could also be applied to both of "external" icons ("Visual Assets") and "internal" icons displayed within the app, or at least X% of the source code could be shared between the "internal" and "external" icon scenarios when it operates like you described.
For comparison purposes, Android supports SVG icons, although the SVG must be converted first (AFAIK). Android has a GUI-based tool that converts the source SVG file to Android's own vector format called VectorDrawable. I think the following items belong in the list of top 10 reasons why Android won the battle between Android versus WinRT/UWP:
- vector graphics files,
- vector icons,
- managed code (Java),
- etc.
This is a good opportunity for Microsoft to change some things in order to attract more developers to UWP.
@verelpode I think it would be more productive to not write these things in a "rant" kind of manner. But I fully agree with the IconSource and Path issues you pointed out, and also the flaws of the assets area. I ran into many of these problems myself.
But you miss some things about assets:
-
It sure makes sense to provide different images for different target sizes. If you simply scale an icon up or down a lot, the result will look poor. If you optimize the icon for a specific resolution (e.g. change line sizes, font sizes, increase or decrease sharpening, add or remove details, add/remove borders), the result will look a lot better. The assets generator is only there to get you started quickly, later you should work on providing better, optimized icons.
-
If you provide only one, high resolution image, then the system must always decode and scale that high res image, even if only a tiny 32x32 icon is to be shown in Windows Explorer. That leads to unneccessarily high CPU and memory usage. So I can see why they force us to ship pre-generated images for different formats and scale factors. But these could also be pre-generated during build, if you do not provide them yourself. A preview in the assets area could show you how good (or bad) your scaled images will look, so you can decide where to optimize and provide better versions, and where to use auto scaling.
-
Adding SVG support will help a lot, but it will not solve all issues, because creating SVG images will require you to use very different tooling. If someone is used to work with Photoshop, they will want to continue with that (and that means, creating multiple scaled and optimized versions). And even if you use SVG, it probably makes sense to optimize for different targets sizes, by adding or removing details, adapting line sizes, etc etc. And I am not 100% sure on this, but I guess decoding SVG is rather CPU intensive, at least for detailed icons. It could still make sense to provide pre-generated (maybe auto-generated during build) JPG or PNG files, at least for icons to be shown in Windows Explorer.
I'd recommend you to create three separate, real proposals, one for the IconSourceElement issues, one for Path issues and one for assets area (that one is not really WinUI related, still it should appear here to create awareness). And I think you should try to just write down things neutrally, without making it a rant. Let's just say that there is still some room for improvement in these areas :)
@lukasf
If you optimize the icon for a specific resolution (e.g. change line sizes, font sizes, increase or decrease sharpening, add or remove details, add/remove borders), the result will look a lot better.
That's unnecessary and brings only an insignificant advantage that is not worthwhile overall. I would recommended against it because it leads to obsessive-compulsive patterns and harmful perfectionism. An obsessive-compulsive artist believes that one version is a lot better than the other version, but the end-users can't see any difference. Many other issues are far more important, but an obsessive-compulsive artist ignores the important issues and spends all his time on unhelpful perfectionism of tiny details that were already very good.
If you provide only one, high resolution image, then the system must always decode and scale that high res image, even if only a tiny 32x32 icon is to be shown in Windows Explorer. That leads to unneccessarily high CPU and memory usage.
If it was my job to write the Windows "Start" menu, then I wouldn't repeat the scaling of the icons every single time they're drawn. I would scale them once-only and then cache and reuse the scaled versions. Thus no problem exists with high processor usage.
If someone is used to work with Photoshop, they will want to continue with that
That's no problem because the suggestion from @charlesroddie already includes support for bitmaps.
I'd recommend you to create three separate, real proposals,
I think your recommendation is good, but a colleague of mine has a different recommendation, and his recommendation convinces me more than your recommendation. His recommendation is that I should "stop wasting so much time writing feedback that will be ignored anyway", and that I should instead write code that eliminates our problems without waiting for Microsoft. He says that if I had stopped writing feedback for Microsoft and instead used the time to write code, then I could have already written solutions to our problems. He says that writing feedback and proposals and waiting for Microsoft takes far more time than writing our own source code that solves the problems. I must acknowledge that his criticism of my strategy could be valid and that I should consider reducing the amount of time that I spend writing feedback and proposals.
For that reason, I must decline your recommendation even though your recommendation was good. Sometimes a good recommendation is short-sighted or doesn't take into account the complete big picture.
I think it would be more productive to not write these things in a "rant" kind of manner.
My communication method has serious problems, but overall on average, my method has a higher rate of efficacy and smaller problems than your preferred method. It doesn't make sense to switch to a communication method that has a lower rate of efficacy on average.
That's unnecessary and brings only an insignificant advantage that is not worthwhile overall. I would recommended against it because it leads to obsessive-compulsive patterns and harmful perfectionism. An obsessive-compulsive artist believes that one version is a lot better than the other version, but the end-users can't see any difference. Many other issues are far more important, but an obsessive-compulsive artist ignores the important issues and spends all his time on unhelpful perfectionism of tiny details that were already very good.
@verelpode The amount of visual detail you can fit in a 16 x 16 resolution is very small. It is best practice to take your 256 x 256 icon, and re-draw it with simpler and fewer details as you go down to 48 x 48, 32 x 32, 24 x 24 etc. The best Icon designs are drawn at these various sizes.
To just resize a more detailed larger icon smaller, would end up a blurry mess. Of course you could design a vector icon at 16 x 16, and scale up, but you will be left with very simple and blocky designs, and strokes would end up being very thick.
You do make it very difficult to take your feedback in a constructive and genuine manner, when you come across as rude and unwillinging to take on board the comments of others.
Could the image asset requirements be simplified and made easier to create - sure. A lot of that would require changes to the Windows Shell, and after some degree of transition from currently supported versions of the OS.
And all the current sizes of icons/images are designed to work with 100% scaling. As that scale factor increases, the amount of image assets, and the amount of pixels available for detailing will increase. Apps will need to account for this.
@mdtauk
The amount of visual detail you can fit in a 16 x 16 resolution is very small.
16x16 is obsolete, but anyway the suggestion from @charlesroddie already includes support for bitmaps and backwards compatibility. One or two small tweaks to his suggestion may be necessary, but mainly it's an excellent suggestion. If you say that his suggestion should be modified to include optional explicit support for 16x16 and 32x32 bitmaps, then I think that's reasonable.
@verelpode I disagree on your stand on image scaling. Blurry, badly scaled images look horrible. When I first saw the explorer icons of my app, I thought, OMG this looks like sh*t. 16x16 might be obsolete, but 48x48 is very alive and looks horrible when scaled down from a detailed high-res image. I believe that the first visual impression on an app has a high impact on the overall impression of the app. People might ditch your app without even trying, if it has a poor visual representation, even if its features are great. And that's not only my opinion, that's also what many studies say. People buy the nice and shiny fruit, even if the pale ones taste better. Sure you can have your own opinion on that. But there are lots of valid arguments to think otherwise.
And about your communication strategy: I don't see that your communication strategy here was particularly successful. As long as WinUI is not open source, you can only implement hacky workarounds inside your apps. If you want a clean solution to come to WinUI, then it will only be taken with a good proposal. There are some very good proposals here, some were already implemented, some are being worked on. As soon as WinUI is open source, I am sure a lot more proposals will be implemented, because then everyone can do it. This whole thing here will only really start once the sources are available. Look at the Windows Community Toolkit, how many controls and improvements have been implemented there already.
Writing lots and lots of bad feedback rants might be a waste of time. Maybe your colleague is right about that. Then I'd say it would be better to write less feedback and concentrate on the most important areas. But write those fewer ones with good quality and in a constructive way, so they have a higher chance to be actually considered.
But maybe you don't even want to give constructive feedback, you just want to rant around. Then it's really just a waste of time...
16x16 icons are far from obsolete. Small icons are required for list views like in Windows Explorer detail or list modes. They are used for status icons and titlebar icons, favicons, etc. They have a valid use case and a good app considers all the use cases and adapts their UI accordingly. You can certainly scale a bigger icon into a title bar, but then you are breaking the UX by wasting space in a Window Frame rather than giving that space to the Content.
This could be summed up as adaptable vs scaling UIs. Adaptable makes sure the icon works best for the placement, position, readability, etc. that is needed for it's use case. Scaling ensures its readable across different DPIs and form factors.
Any x*x icons are obsolete since Windows Vista which introduced good support for dpi. Since scaling in windows can be anything, you would need to support every possible integer x of you do it that way. @verelpode is being constructive with detailed analysis. If you want images to vary by size and be sharp then two or three svgs should be used for the same icon.
@dragonwolf83
16x16 icons are far from obsolete.
Although I view 16x16 as obsolete, and although I view @lukasf's varying line thicknesses as overkill, nevertheless I would be willing to support a modified version of @charlesroddie's suggestion that supports those abilities, as follows. A single icon would consist of a list of images. Each image in the list can be either SVG or PNG. Thus a single icon consists of zero or more SVG images and zero or more PNG images.
The size of each PNG in the source image list should be determined by the app developer's own preferences (not by Visual Studio). For example, an app developer would be able to configure a single icon to consist of these 4 source images:
- An SVG image.
- A 512x512 PNG image.
- A 32x32 PNG image.
- A 16x16 PNG image.
I believe @lukasf, @mdtauk, and @dragonwolf83 should be happy now because the suggested plan includes support for what they want.
Visual Studio shouldn't stop you from supplying a non-standard size. For example, if you want to display wide 48x32 icons inside your app, then Visual Studio shouldn't stop you from supplying a 48x32 PNG image. The sizes of the supplied source images should be your own choice. When an icon is rendered at runtime, obviously it should inspect the list of images in the icon, and select whichever one is the best/closest match for the destination rectangle and resolution.
@charlesroddie
If you want images to vary by size and be sharp then two or three svgs should be used for the same icon.
Good point. I had already thought about multiple PNG images in the same icon, but I didn't realize that multiple SVG images in the same icon could be used to support varying line thicknesses, font sizes, borders. Note this idea of multiple SVG images only succeeds if each SVG image can be marked with a width and height, but SVG already supports this, IIRC. Even if I've remembered incorrectly and SVG doesn't support storage of a width and height, it would be trivially easy to separately store a width and height with each SVG image in the icon. So the point is, yes, a single icon can consist of a list of images, and each image should be either SVG or PNG.
@lukasf
Blurry, badly scaled images look horrible.
When scaling an image at runtime, some software still uses a very old and obsolete scaling algorithm that delivers poor image quality: The "Nearest Neighbor" algorithm. The use of this obsolete algorithm is a defect in those pieces of software. Those defective programs should be corrected to use the bicubic image scaling algorithm, which delivers much better image quality. Decades ago, CPU's had insufficient power to quickly perform bicubic at runtime, and GPU's didn't even exist, therefore the fast-but-bad "Nearest Neighbor" algorithm was the only choice at runtime, and bicubic could only be performed prior to runtime in separate program such as Photoshop.
Nowadays every computer has a GPU, and every tablet and smartphone has integrated GPU-like abilities, thus bicubic should be performed at runtime. Furthermore, in order to further enhance speed, bicubic scaling can be performed once and then cached and reused (not repeated every time an icon is rendered), as I mentioned in a previous message re the implementation of the Windows "Start" menu. Thus software that still uses "Nearest Neighbor" is incorrectly written and needs to be fixed to use bicubic.
"Nearest Neighbor" is a good option if dealing with pixel art and defined scaling ratios.
I think it could be useful to sum up what your request is, as opposed to a long and detailed explanation of what is broken.
Based on looking through the posts, I think you have a number of asks that are all related in some ways.
- An option to resize FontIcon glyphs with width and height, and not just fontsizing;
- Choice of scaling algorithms for bitmap icons/images;
- Ability to use BitmapStreams rather than loading resource files;
- The ability for Windows to use Vector files for Icons throughout the OS Shell;
- (supposition) Grouping vector files based on TargetSize as a single icon;
- Easier way to assign/generate/create App resource imagery;
- Reduce the variations required, and remove redundant image formats and sizes;
- Fitting non-standard sized images to the nearest applicable size;
- Rationalise the Coloured, Unplated, Plated, Monochrome icon options for the shell;
- Improve the previews for App resources in the packaging UI;
@mdtauk
I think it could be useful to sum up what your request is, as opposed to a long and detailed explanation of what is broken.
Yes, you're right, but why should I work for a wealthy corporation (such as Microsoft) for free? It would be wildly unreasonable to expect me to work as if I'm a Microsoft employee, in return for $0 of salary for my hard work. To be ethical and fair, software engineers need to be paid a reasonable salary in return for their long hours of hard work. Ethical and legal working conditions. Also, I'm not a pseudo-religious open source fanatic who works two jobs simultaneously; a so-called "day job" plus a so-called "night job". An unpaid "night job" that is quasi-illegal in regards to max allowed/legal working hours per week. Open source isn't bad, but open source fanaticism is very bad -- it causes much harm to society and to companies as well. (That's not a complaint about you @mdtauk. I know you're no fanatic. That's a complaint about other people, not anyone here in issue #1494.)
Thus you and @lukasf are correct in saying that properly-written proposals would be better, but I am not going to do that work because it would make me feel as if I'm being unethically exploited/abused.
I believe that it would have been less work to write 2 or 3 compact, focused proposals for the improvements that would be most valueable for you, compared to the very lengthy and overly detailed write down of everything that is wrong.
It's up to you to decide how much time you spend here. Microsoft won't pay you for creating issues here, obviously. Remember that creating an issue is usually only a tiny fraction of work, compared to the work required to actually resolve one of these issues.
Since it seems like @verelpode won't write a proposal, I would like to step in and do this since it would be hard for the WinUI team and the community to come up with feasible solutions solely from this discussion.
However I am not quite familiar with all the obstacles that are combined with using custom icons in UWP and WinUI, thus I will base it on the list @mdtauk kindly created in this issue (comment link: https://github.com/microsoft/microsoft-ui-xaml/issues/1494#issuecomment-576251398)
There seem to be two large areas where there should be improvement:
Using icons in app
- Use SVG
- Option to resize FontIcon glyphs with width and height, and not just fontsizing
- Choice of scaling algorithms for bitmap icons/images
- Ability to use BitmapStreams rather than loading resource files
- Easier way to assign/generate/create App resource imagery
App/tile icon
- Abilitiy to use SVG as app icon
- Reduce the variations required, and remove redundant image formats and sizes
- Make it clear what icon is used for what and why the developer should provide it
Are there any points missing @mdtauk , @charlesroddie, @verelpode , @lukasf, @moshegutman, @dragonwolf83 ?
@verelpode Mind expanding on the open source "fanaticism" ? 😅 Are there any cases you can point out where this has happened here? Also mind elaborating in why you would feel being "unethically exploited/abused" if you were writing a proposal? Keep in mind that writing a proposal is one of the best ways to ensure that your ideas get understood correctly.