You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Functional Converters is a library that allows you to define converters using a single class, with converters defined as functions rather than their own classes.
Designed for WPF, may work with UWP and MAUI, but not tested yet.
Class Setup
All custom converters inherit from the ExtensibleConverter class. You only need one class that contains all converters, but you can define more if you wish.
Note the string parameter passed into the MyConverters constructor. It makes the XAML cleaner, but if you don't define this parameter, you can still use your converters in XAML like this:
Each converter is defined as a static method, returning a type of either:
SingleConverter: For a single input and output
MultiConverter: For multiple inputs and a single output. Note that TInput is implicitly converted to an array of the input type.
Example 1: SingleConverter using lambda syntax
Converters can entirely be defined using lambda syntax, which is the most concise way to define them. The convertBackFunction is also optional, so you can omit this entirely in one-way conversions.
Multiconverters are defined in the same way as single converters.
However, note that while the MultiConverter class is defined as MultiConverter, the TInput type is implicitly converted to TInput[] later.
This means that for a boolean multiconverter, the convertFunction will take in a bool[] parameter, while the MultiConverter class itself is still defined as MultiConverter, without the [].
Notice in all the above examples, you have to include the object parameter in the function signature.
FunctionalConverters provides helper CreateConverter and CreateMultiConverter methods that can abstract some of this away and make it even simpler to define your converters.
//Not using the helper method publicstaticSingleConverter<bool,Visibility>BooleanToVisibility() { returnnewSingleConverter<bool,Visibility>( convertFunction:(input,parameter)=>input?Visibility.Visible:Visibility.Collapsed, convertBackFunction:(output,parameter)=>output==Visibility.Visible ); } //Using the CreateConverter helper method publicstaticSingleConverter<bool,Visibility>BooleanToVisibility() { returnCreateConverter<bool,Visibility>( convertFunction: input =>input?Visibility.Visible:Visibility.Collapsed, convertBackFunction: output =>output==Visibility.Visible ); }
FunctionalConverters uses some reflection to find the converter methods in the MarkupExtension.ProvideValue method.
I am not totally familiar with the MarkupExtension class, but I think this is only called once per converter. I cache the returned methods just in case, but if I'm correct the performance hit is small and once-off only.
As far as the actual converter performance once initialised, here's the results of benchmarking with BenchmarkDotNet:
| Method | Mean | Error | StdDev | Ratio | Gen0 | Allocated | Alloc Ratio | |--------------------------|---------:|---------:|---------:|------:|-------:|----------:|------------:| | IValueConverter*|23.68 ns |1.453 ns |0.080 ns |1.00|0.0029|48 B |1.00| | SingleConverter |23.66 ns |0.808 ns |0.044 ns |1.00|0.0029|48 B |1.00| |||||||| | IMultiValueConverter*|51.78 ns |3.030 ns |0.166 ns |1.00|0.0081|136 B |1.00| | MultiConverter |73.94 ns |9.355 ns |0.513 ns |1.43|0.0114|192 B |1.41|
The SingleConverter is roughly on par with the baseline IValueConverter implementation.
The MultiConverter is slower, but this is likely due to the fact that it has to convert the input to an array first. While the relative performance is worse by ~43%, the absolute performance is still very fast at ~74ns.
If anyone knows more about how the MarkupExtension class works, please let me know if this is a performance concern. I could implement additional caching or switch to delegates instead of reflection but my naive testing didn't identify any real performance changes with those methods (this may change if there are many converters however).
About
Create IValueConverters in WPF more easily using functional declarations