Avalonia icon indicating copy to clipboard operation
Avalonia copied to clipboard

Consider moving theme-specific converters to theme assemblies

Open MrJul opened this issue 6 months ago • 3 comments

Is your feature request related to a problem? Please describe.

As discussed in https://github.com/AvaloniaUI/Avalonia/pull/18718#issuecomment-2984454059, Avalonia currently has several converters used by only its themes, Fluent and Simple. Examples of such converters: MenuScrollingVisibilityConverter and MarginMultiplierConverter.

These converters currently live in the Avalonia.Controls assembly so they can easily be shared. However, we shouldn't "bloat" that assembly with unnecessary types that aren't used outside of themes and are effectively part of the public Avalonia.Controls API.

Plus, the behavior of these converters isn't really documented: we might very well adjust them depending on theme requirements.

Describe the solution you'd like

Move the converters to the Avalonia.Themes.Fluent and Avalonia.Themes.Simple projects. The file would be linked between the two projects to avoid source code duplication, but the type would effectively exist in both theme assemblies.

While not ideal, this is what WPF does (see ProgressBarBrushConverter). This allows the theme to be self-contained.

Describe alternatives you've considered

Do nothing and keep the converters where they are.

Additional context

No response

MrJul avatar Jun 18 '25 14:06 MrJul

We might also consider making all the converters sealed. A converter really doesn't need to be open for extensibility.

MrJul avatar Jun 18 '25 14:06 MrJul

I think some applications have both fluent and simple installed, will the linkage cause any conflict?

rabbitism avatar Jun 18 '25 14:06 rabbitism

I think some applications have both fluent and simple installed, will the linkage cause any conflict?

It might. We should probably change the converters' namespace to match the current assembly, avoiding conflicts.

That said, even if they share the same namespace, problems will occur only if both themes are referenced and the converter is explicitly used in C#, which seems a bit unlikely (but not impossible).

MrJul avatar Jun 18 '25 15:06 MrJul

Another option I randomly thought about - to continue our approach/consistency with static converters:

public static class ControlConverters
{
     public static IMultiValueConverter MenuScrollingVisibility = /* */;
     public static IValueConverter TreeIndent = /* */;
}

public static class MarginConverters
{
     public static IValueConverter Left = /* */;
     public static IValueConverter Top= /* */;
     public static IValueConverter Right = /* */;
     public static IValueConverter Bottom = /* */;
    /* duplicate for the any possible combination */
}
public static class CornerRadiusConverters
{
     public static IValueConverter TopLeft = /* */;
     public static IValueConverter TopRight= /* */;
     public static IValueConverter BottomRight = /* */;
     public static IValueConverter BottomLeft= /* */;
    /* duplicate for the any possible combination */
}

public static class StringConverters
{
    // replacement for Avalonia.Controls/Converters/StringFormatConverter.cs
    public static IMultiValueConverter DynamicFormat =  /* */;
}

Goal here is to make these converters less theme specific, and more generally applicable controls. Except ControlConverters, but we don't have many of these.

Also,

  1. Replace EnumToBoolConverter with ObjectConverters.Equal
  2. Replace PlatformKeyGestureConverter with TemplateBindng.StringFormat (should work?)
  3. We can combine CornerRadiusFilterConverter and CornerRadiusToDoubleConverter by checking target type. Or just split into different static converters.
  4. Remove StringFormatValueConverter (I think it was used internally for old Bindings implementation, but not anymore)
  5. Same with StringFormatMultiValueConverter, or make it internal (it's still used internally for MultiBinding)
  6. Converters from Avalonia.Controls.ColorPicker also can be incorporated into Color/BrushConverters static class as much as possible.

maxkatz6 avatar Jun 21 '25 09:06 maxkatz6

Instead of class ControlConverters, we also can move these converters as static properties of the control themselves (i.e., static TreeViewItem.IntentConverter).

maxkatz6 avatar Jun 21 '25 09:06 maxkatz6

Also, it was always possible to combine markup extensions and converters, allowing to pass extra arguments and context (which value converters commonly lack). Not sure if we want to do that in our stable API, but as an option to consider.

Example from my older code, not an actual API for Avalonia, but a technique:

 <Image Source="{Binding IconResources, Converter={converters:ResourceConverter}}" />

Image

maxkatz6 avatar Jun 21 '25 09:06 maxkatz6