ModernWpf icon indicating copy to clipboard operation
ModernWpf copied to clipboard

Cannot set AppBarButton Icon from Style

Open wmrutten opened this issue 4 years ago • 8 comments

Hi @Kinnara,

thank you for all your work on this great library!

I tried to define a Style for an AppBarButton that speciffes the AppBarButton.Icon property. Apparently, the Style only works on a single instance of the button. If multiple buttons apply the same style, then only the last button will display the icon.

The Icon property is of type IconElement : FrameworkElement. AFAIK, an element can only be used once in the visual tree. I haven't been able to find a workaround for this current limitation.

Usually, control properties are either Freezable or a pair of { Content, ContentTemplate }, to allow templating.

Maybe the new IconSource provides an elegant solution to this problem?

wmrutten avatar Nov 30 '20 10:11 wmrutten

But the AppBarButton (both UWP XAML and WinUI 3.0) don't support the IconSource classes yet. It would be better to open a feature request on the WinUI repo. We should also let them know.

One way to solve this would be to make a custom markup extension. (a temporary workaround. Not elegant but will do the job) If you can't make a custom markup extension that will return an IconElement instance, then let me know. I could provide you some code samples.

ShankarBUS avatar Nov 30 '20 10:11 ShankarBUS

@wmrutten,

As for the workaround, the Windows-Community-Toolkit provides the markup extensions for IconElements. The same extensions are also provided in the ModernWpf-Community-Toolkit. You can readily use the toolkit with a ModernWpf application.

You can either include just these files in your code https://github.com/ModernWpf-Community/ModernWpfCommunityToolkit/tree/master/ModernWpf.Toolkit.UI/Extensions/Markup (BitmapIconExtension, FontIconExtension and SymbolIconExtension are enough for your case) or reference the ModernWpf.Toolkit.UI nuget package and use it instead.

This MS Doc demonstrates how to use the markup extensions https://docs.microsoft.com/en-us/windows/communitytoolkit/extensions/iconmarkupextensions

The toolkit still lacks a markup extension for PathIcon though. Are these enough for you? (for now?)

ShankarBUS avatar Nov 30 '20 11:11 ShankarBUS

Hi @ShankarBUS,

thank you for your feedback!

i am using a markup extension. But when assigning AppBarButton.Icon from a Style, the markup extension is evaluated only once (when parsing the style). The resulting IconElement is then (illegally) re-used for all instances that apply the style. However each element should receive it's own IconElement instance. Not sure how to work around this - if it is even possible? I think this is why a Control should not expose properties of type FrameworkElement, but instead allow the consumer to assign a template. For now, I simply stopped using Styles (for AppBarButton).

wmrutten avatar Nov 30 '20 13:11 wmrutten

Oh! Sorry I misread your statement 😅.

I didn't notice you were referring to a style. Yeah in that case a markup extension won't work.

ShankarBUS avatar Nov 30 '20 15:11 ShankarBUS

OK, thank you for confirming my suspicion.

Then I guess this is actually an issue of the original UWP AppBarButton control. Unless the WPF behavior is different from UWP?

wmrutten avatar Nov 30 '20 17:11 wmrutten

This is actually possible in WPF, thanks to the x:Shared attribute:

<ui:SymbolIcon x:Key="SaveIcon" Symbol="Save" x:Shared="False" />

<Style x:Key="SaveButtonStyle" TargetType="ui:AppBarButton">
    <Setter Property="Icon" Value="{StaticResource SaveIcon}" />
    <Setter Property="Label" Value="Save" />
</Style>
<ui:CommandBar>
    <ui:AppBarButton Style="{StaticResource SaveButtonStyle}" />
    <ui:AppBarButton Style="{StaticResource SaveButtonStyle}" />
    <ui:AppBarButton Style="{StaticResource SaveButtonStyle}" />
</ui:CommandBar>

Kinnara avatar Dec 06 '20 16:12 Kinnara

@Kinnara, 👏👏👏 That's it, problem solved!

ShankarBUS avatar Dec 06 '20 16:12 ShankarBUS

Hi @Kinnara , thank you for your feedback.

Indeed, the issue is related to resource sharing. I am aware of the x:Shared attribute, it fixes the problem for global resources declared in XAML.

In this case, I was trying to provide the icon resource in a Style through a (custom) markup extension that returns a (custom) FontIcon, programmatically. The markup extension would need to return a separate FontIcon instance for each target control that the style is applied to, similar to x:Shared behavior. Maybe this is possible by hooking the target control from the markup extension, but I didn't explore any further.

Nonetheless, I understand the motivations for this library to stay close to the original UWP interface and I'm perfectly happy w/o support for AppBarButton styling.

Thanks for all you hard work, guys. This library provides great UI improvements that are happily received by our app users. Quite amazing to see WinUI design running on an old Windows 7 (!) machine.

Kudos and keep it up!

wmrutten avatar Dec 18 '20 19:12 wmrutten