wpf-rule-converter-patterns — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited wpf-rule-converter-patterns (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Standards for implementing IValueConverter in wpf-dev-pack projects.
Every converter is a MarkupExtension so it can be used directly in XAML without declaring a resource, and ProvideValue returns a single shared instance (converters are stateless, so a shared instance is safe and avoids ResourceDictionary clutter). This is the canonical converter pattern, matching the /wpf-dev-pack:make-wpf-converter scaffolder and the using-converter-markup-extension knowledge topic. Pick this one pattern — do NOT also expose a separate static Instance property.
Derive from a small base class (the scaffolder generates it once per project):
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) => _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("ConvertBack is not supported.");
}
public sealed class BoolToVisibilityConverter : ConverterMarkupExtension<BoolToVisibilityConverter>
{
public override object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (value is null || value == DependencyProperty.UnsetValue)
return Visibility.Collapsed;
var invert = parameter is "Invert" or "invert";
return (value is bool b && (b ^ invert)) ? Visibility.Visible : Visibility.Collapsed;
}
}Usage in XAML (no ResourceDictionary entry required):
<TextBlock Visibility="{Binding IsActive,
Converter={converters:BoolToVisibilityConverter}}" />Converters must be pure functions:
DateTime.Now inside Convert)If conversion logic requires external context, pass it via the ConverterParameter or via a MultiBinding with IMultiValueConverter.
Always handle both null and DependencyProperty.UnsetValue as the first check in Convert:
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is null || value == DependencyProperty.UnsetValue)
return DependencyProperty.UnsetValue; // or a safe default
// normal conversion logic
}Returning DependencyProperty.UnsetValue from Convert signals WPF to use the property's default value rather than throwing a binding error.
Inside a ControlTemplate, use TemplateBinding (not Binding) to reference the templated parent's properties. TemplateBinding is a lightweight one-way binding that avoids the overhead of a full Binding object.
<!-- Correct: TemplateBinding for ControlTemplate property references -->
<ControlTemplate TargetType="{x:Type local:MyButton}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="4">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
</ControlTemplate><!-- Incorrect: Binding with RelativeSource is verbose and slower -->
<Border Background="{Binding Background,
RelativeSource={RelativeSource TemplatedParent}}">Use Binding with RelativeSource=TemplatedParent only when you need two-way binding or a converter applied to a templated-parent property — TemplateBinding is one-way only and does not support converters directly.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.