WpfAnalyzers

repository·master·Indexed 41 days ago

https://github.com/dotnetanalyzers/wpfanalyzers

A set of Roslyn analyzers for WPF (Windows Presentation Foundation) projects designed to improve code quality and adherence to best practices. It provides diagnostic checks for DependencyProperty registration, event handling, and the correct usage of attributes like [TemplatePart] and [ValueConversion]. Supports Visual Studio 2015 (1.x), 2017 (2.x), 2019 (3.x), and 2022+ (4.x).

Tokens
49K
Snippets
131
Records
220
Agent score
2%

What's inside WpfAnalyzers

  1. Understand the WPF0082 rule: [ConstructorArgument] must match

    master
    The WPF0082 rule ensures that the name of an attribute argument provided in a constructor must match the name of the corresponding parameter in the attribute's constructor definition. This rule belongs to the WpfAnalyzers.MarkupExtension category and is enabled by default with a Warning severity.
  2. WPF0070: Add default field to converter

    master

    WPF0070 is an analyzer rule that suggests adding a Default field or property to classes implementing IValueConverter if they have no mutable members.

    Motivation: Adding a static Default member allows you to use the converter in XAML via the x:Static markup extension (e.g., Converter={x:Static converters:FooConverter.Default}). This is often simpler and more explicit than defining the converter within a Resource Dictionary.

  3. Suppress WPF0023 using #pragma directives

    master

    You can suppress the WPF0023 warning locally within a block of code or globally for an entire file using C# #pragma directives.

    #pragma warning disable WPF0023 // The callback is trivial, convert to lambda
    Code violating the rule here
    #pragma warning restore WPF0023 // The callback is trivial, convert to lambda

    To disable the rule for the entire file, place this at the top:

    #pragma warning disable WPF0023 // The callback is trivial, convert to lambda
  4. Fix WPF0015: Registered owner type must inherit DependencyObject

    master

    The WPF0015 analyzer rule detects when a DependencyProperty is registered with an owner type that does not inherit from DependencyObject. This typically occurs when attempting to register an attached property using DependencyProperty.Register instead of DependencyProperty.RegisterAttached (or RegisterAttachedReadOnly).

    To fix this violation, you have two primary options:

    1. Use Attached Property Registration: If the owner type is a static class (which cannot inherit from DependencyObject), change the registration method to DependencyProperty.RegisterAttached or DependencyProperty.RegisterAttachedReadOnly.
    2. Inherit from DependencyObject: If the owner type is intended to be a standard property owner, ensure the class inherits from System.Windows.DependencyObject.
    using System.Windows;
    
    public static class Foo
    {
        // FIX: Use RegisterAttached instead of Register for static classes
        public static readonly DependencyProperty BarProperty = DependencyProperty.RegisterAttached(
            "Bar",
            typeof(int), 
            typeof(Foo), 
            new FrameworkPropertyMetadata(
                default(int), 
                FrameworkPropertyMetadataOptions.Inherits));
    
        public static void SetBar(DependencyObject element, int value)
        {
            element.SetValue(BarProperty, value);
        }
    
        public static int GetBar(DependencyObject element)
        {
            return (int) element.GetValue(BarProperty);
        }
    }
  5. Suppress the WPF0010 warning

    master

    You can suppress WPF0010 violations using several methods:

    1. #pragma directive: Disable the warning for a specific block of code or for the entire file.
    2. [SuppressMessage] attribute: Use the System.Diagnostics.CodeAnalysis.SuppressMessage attribute to suppress the warning with a specific justification.
    3. Ruleset file: Configure the severity via a standard .NET ruleset file.
    // Using #pragma to disable/restore for a specific block
    #pragma warning disable WPF0010 // Default value type must match registered type
    Code violating the rule here
    #pragma warning restore WPF0010 // Default value type must match registered type
    
    // Or disable for the whole file
    #pragma warning disable WPF0010
    
    // Using [SuppressMessage] attribute
    [System.Diagnostics.CodeAnalysis.SuppressMessage("WpfAnalyzers.DependencyProperty", 
        "WPF0010:Default value type must match registered type", 
        Justification = "Reason...")]
  6. Suppress WPF0032 using the [SuppressMessage] attribute

    master

    To suppress the WPF0032 violation using an attribute, use [System.Diagnostics.CodeAnalysis.SuppressMessage]. You must specify the category WpfAnalyzers.DependencyProperty and the specific rule ID/description.

    [System.Diagnostics.CodeAnalysis.SuppressMessage("WpfAnalyzers.DependencyProperty", 
        "WPF0032:Use same dependency property in get and set", 
        Justification = "Reason...")]
  7. Suppress the WPF0121 violation using [SuppressMessage] attribute

    master

    To suppress the WPF0121 violation using an attribute, apply [System.Diagnostics.CodeAnalysis.SuppressMessage] to the relevant code element. You must specify the category WpfAnalyzers.RoutedCommand and the exact rule ID and description.

    [System.Diagnostics.CodeAnalysis.SuppressMessage("WpfAnalyzers.RoutedCommand", 
        "WPF0121:Register containing type as owner for routed command", 
        Justification = "Reason...")]
  8. Fix WPF0007: Name of ValidateValueCallback should match registered name

    master

    The WPF0007 rule ensures that the ValidateValueCallback method name matches the name of the Dependency Property it is validating. This is a stylistic rule to improve code readability and maintainability.

    Violation Example: If you register a property named Bar but provide a callback named WrongName, a violation is triggered.

    How to fix: Rename the callback method so that it includes the property name (e.g., if the property is Bar, name the callback BarValidateValue).

    public class FooControl : Control
    {
        public static readonly DependencyProperty BarProperty = DependencyProperty.Register(
            nameof(Bar),
            typeof(int),
            typeof(FooControl),
            new PropertyMetadata(default(int)),
            BarValidateValue); // Callback name matches property name
    
        public int Bar
        {
            get { return (int)this.GetValue(BarProperty); }
            set { this.SetValue(BarProperty, value); }
        }
    
        private static bool BarValidateValue(object value)
        {
            return (int)value >= 0;
        }
    }
  9. Fix WPF0006: Name of CoerceValueCallback should match registered name

    master

    The WPF0006 rule ensures that the name of a CoerceValueCallback method matches the name of the DependencyProperty it is registered with. This is a stylistic rule to improve code readability and maintainability in WPF development.

    Violation Example: If you register a property named BarProperty but provide a callback named WrongName, a violation is triggered.

    How to fix: Rename the callback method to follow the pattern Coerce[PropertyName] (e.g., CoerceBar).

    // Correct implementation
    public class FooControl : Control
    {
        public static readonly DependencyProperty BarProperty = DependencyProperty.Register(
            nameof(Bar),
            typeof(int),
            typeof(FooControl),
            new PropertyMetadata(
                default(int),
                null,
                CoerceBar)); // Name matches the property 'Bar'
    
        public int Bar
        {
            get { return (int)this.GetValue(BarProperty); }
            set { this.SetValue(BarProperty, value); }
        }
    
        private static object CoerceBar(DependencyObject d, object baseValue)
        {
            return baseValue;
        }
    }
  10. Fix WPF0003: CLR property for a DependencyProperty should match registered name

    master

    The WPF0003 analyzer ensures that the name of a CLR property accessor matches the name used when registering its corresponding DependencyProperty. While technically legal to use different names, mismatching them creates a confusing API that violates standard WPF conventions.

    Violation Example: In the example below, the DependencyProperty is registered as Title, but the CLR property is named HighlightBrush.

    using System.Windows;
    public class MyControl : FrameworkElement
    {
        public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(
            nameof(Title),
            typeof(string),
            typeof(MyControl),
            new PropertyMetadata(default(string)));
    
        public string HighlightBrush
        {
            get { return (string)this.GetValue(TitleProperty); }
            set { this.SetValue(TitleProperty, value); }
        }
    }

    Correct Implementation: Rename the CLR property to match the registered name (Title).

    using System.Windows;
    public class MyControl : FrameworkElement
    {
        public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(
            nameof(Title),
            typeof(string),
            typeof(MyControl),
            new PropertyMetadata(default(string)));
    
        public string Title
        {
            get { return (string)this.GetValue(TitleProperty); }
            set { this.SetValue(TitleProperty, value); }
        }
    }