using-converter-markup-extension
0
总安装量
1
周安装量
安装命令
npx skills add https://github.com/christian289/dotnet-with-claudecode --skill using-converter-markup-extension
Agent 安装分布
amp
1
cline
1
opencode
1
cursor
1
continue
1
kimi-cli
1
Skill 文档
Using Converter Markup Extension
Combine MarkupExtension with IValueConverter for direct XAML usage without resource declarations.
Why Markup Extension Converters?
| Aspect | StaticResource Converter | MarkupExtension Converter |
|---|---|---|
| Declaration | Required in Resources | Not required |
| XAML Usage | {StaticResource MyConverter} |
{local:MyConverter} |
| Singleton | Manual implementation | Built-in lazy singleton |
| Boilerplate | More | Less |
Base Classes
IValueConverter Base (.NET 7+)
namespace MyApp.Converters;
public abstract class ConverterMarkupExtension<T> : MarkupExtension, IValueConverter
where T : class, new()
{
private static readonly Lazy<T> _converter = new(() => new T());
public override object ProvideValue(IServiceProvider serviceProvider)
{
return _converter.Value;
}
public abstract object? Convert(
object? value,
Type targetType,
object? parameter,
CultureInfo culture);
public virtual object? ConvertBack(
object? value,
Type targetType,
object? parameter,
CultureInfo culture)
{
throw new NotSupportedException();
}
}
IMultiValueConverter Base
namespace MyApp.Converters;
public abstract class MultiConverterMarkupExtension<T> : MarkupExtension, IMultiValueConverter
where T : class, new()
{
private static readonly Lazy<T> _converter = new(() => new T());
public override object ProvideValue(IServiceProvider serviceProvider)
{
return _converter.Value;
}
public abstract object? Convert(
object?[] values,
Type targetType,
object? parameter,
CultureInfo culture);
public virtual object?[] ConvertBack(
object? value,
Type[] targetTypes,
object? parameter,
CultureInfo culture)
{
throw new NotSupportedException();
}
}
Example Converters
BoolToVisibilityConverter
public sealed class BoolToVisibilityConverter : ConverterMarkupExtension<BoolToVisibilityConverter>
{
public override object? Convert(
object? value,
Type targetType,
object? parameter,
CultureInfo culture)
{
if (value is not bool boolValue)
return Visibility.Collapsed;
var invert = parameter is "Invert" or "invert";
return (boolValue ^ invert) ? Visibility.Visible : Visibility.Collapsed;
}
}
XAML Usage:
<Button Visibility="{Binding IsEnabled, Converter={local:BoolToVisibilityConverter}}"/>
<!-- With parameter -->
<Button Visibility="{Binding IsDisabled, Converter={local:BoolToVisibilityConverter}, ConverterParameter=Invert}"/>
NullToVisibilityConverter
public sealed class NullToVisibilityConverter : ConverterMarkupExtension<NullToVisibilityConverter>
{
public override object? Convert(
object? value,
Type targetType,
object? parameter,
CultureInfo culture)
{
var isNull = value is null;
var invert = parameter is "Invert";
return (isNull ^ invert) ? Visibility.Collapsed : Visibility.Visible;
}
}
StringFormatConverter
public sealed class StringFormatConverter : ConverterMarkupExtension<StringFormatConverter>
{
public override object? Convert(
object? value,
Type targetType,
object? parameter,
CultureInfo culture)
{
if (parameter is not string format)
return value?.ToString();
return string.Format(culture, format, value);
}
}
XAML Usage:
<TextBlock Text="{Binding Price, Converter={local:StringFormatConverter}, ConverterParameter='{}{0:C}'}"/>
FullNameConverter (Multi)
public sealed class FullNameConverter : MultiConverterMarkupExtension<FullNameConverter>
{
public override object? Convert(
object?[] values,
Type targetType,
object? parameter,
CultureInfo culture)
{
if (values.Length < 2)
return string.Empty;
var firstName = values[0]?.ToString() ?? string.Empty;
var lastName = values[1]?.ToString() ?? string.Empty;
return $"{firstName} {lastName}".Trim();
}
}
XAML Usage:
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{local:FullNameConverter}">
<Binding Path="FirstName"/>
<Binding Path="LastName"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
GlobalUsings.cs
global using System;
global using System.Globalization;
global using System.Windows;
global using System.Windows.Data;
global using System.Windows.Markup;
Migration from StaticResource
Before
<Window.Resources>
<local:BoolToVisibilityConverter x:Key="BoolToVisibility"/>
</Window.Resources>
<Button Visibility="{Binding IsVisible, Converter={StaticResource BoolToVisibility}}"/>
After
<!-- No resource declaration needed -->
<Button Visibility="{Binding IsVisible, Converter={local:BoolToVisibilityConverter}}"/>
File Structure
MyApp/
âââ Converters/
â âââ ConverterMarkupExtension.cs # Base class
â âââ MultiConverterMarkupExtension.cs # Multi base class
â âââ BoolToVisibilityConverter.cs
â âââ NullToVisibilityConverter.cs
â âââ StringFormatConverter.cs
Checklist
- Inherit from
ConverterMarkupExtension<T>orMultiConverterMarkupExtension<T> - Class is
sealed(no inheritance needed) - Handle null input gracefully
- Return
DependencyProperty.UnsetValuefor invalid input if needed - Use
ConverterParameterfor variations instead of multiple converters