From a2b9a9f5c46ec81f132249330121e31f695d1ecd Mon Sep 17 00:00:00 2001 From: Julian lechner Date: Wed, 16 Sep 2026 15:29:33 +0200 Subject: [PATCH] refactor(rules): split wpf.md into index + references Co-Authored-By: Claude Haiku 4.5 --- shared/rules/wpf.md | 375 ------------------ shared/rules/wpf/index.md | 34 ++ .../references/architecture-and-quality.md | 82 ++++ .../wpf/references/collections-and-xaml.md | 49 +++ .../wpf/references/commands-and-async.md | 46 +++ .../rules/wpf/references/mvvm-and-binding.md | 60 +++ .../wpf/references/resources-and-lifecycle.md | 58 +++ .../wpf/references/security-and-errors.md | 53 +++ 8 files changed, 382 insertions(+), 375 deletions(-) delete mode 100644 shared/rules/wpf.md create mode 100644 shared/rules/wpf/index.md create mode 100644 shared/rules/wpf/references/architecture-and-quality.md create mode 100644 shared/rules/wpf/references/collections-and-xaml.md create mode 100644 shared/rules/wpf/references/commands-and-async.md create mode 100644 shared/rules/wpf/references/mvvm-and-binding.md create mode 100644 shared/rules/wpf/references/resources-and-lifecycle.md create mode 100644 shared/rules/wpf/references/security-and-errors.md diff --git a/shared/rules/wpf.md b/shared/rules/wpf.md deleted file mode 100644 index ce0e074..0000000 --- a/shared/rules/wpf.md +++ /dev/null @@ -1,375 +0,0 @@ -# WPF Code Guidelines - -* Use modern C# and current .NET/WPF conventions. -* Keep UI, application logic and domain logic clearly separated. -* Prefer MVVM for non-trivial views. -* Keep code-behind minimal. -* Use code-behind only for view-specific behavior that does not belong in the ViewModel. -* Avoid business logic in views. -* Avoid direct service access from controls. -* Keep dependencies explicit and testable. -* Prefer composition over inheritance. -* Avoid unnecessary abstractions and framework wrappers. -* Follow the existing project architecture unless there is a strong reason to change it. - -## MVVM - -* Keep ViewModels focused on presentation state and commands. -* Do not put UI element references into ViewModels. -* Do not access `Window`, `UserControl`, `DispatcherObject` or visual tree elements from ViewModels. -* Avoid direct navigation, dialogs or message boxes from ViewModels without an abstraction when testability matters. -* Prefer explicit application services for navigation, dialogs and external interactions. -* Keep domain logic outside ViewModels. -* Do not use ViewModels as general-purpose service containers. -* Keep ViewModel dependencies minimal. -* Prefer immutable or readonly state where practical. -* Avoid duplicated derived state. -* Keep state transitions predictable. - -## Data Binding - -* Prefer data binding over manual UI synchronization. -* Use strongly typed properties. -* Use appropriate binding modes. -* Prefer `OneWay` when two-way updates are not required. -* Use `TwoWay` only when the UI must modify the source. -* Avoid unnecessary `UpdateSourceTrigger=PropertyChanged` for expensive operations. -* Keep binding paths simple and stable. -* Avoid deeply nested binding paths. -* Do not hide broken bindings. -* Treat binding errors as real defects. -* Use `FallbackValue` and `TargetNullValue` only when they reflect intended behavior. -* Avoid excessive converters. -* Prefer exposing correctly shaped state from the ViewModel over complex converter logic. -* Avoid `MultiBinding` when simpler state modeling is clearer. -* Do not put business logic into converters. - -## Property Change Notifications - -* Implement property change notifications consistently. -* Avoid raising `PropertyChanged` unnecessarily. -* Raise notifications only when values actually change. -* Keep dependent property notifications explicit. -* Avoid hidden notification chains that are difficult to reason about. -* Prefer reusable base implementations only when they reduce duplication without obscuring behavior. -* Do not use reflection-based notification mechanisms unless there is a concrete benefit. - -## Commands - -* Prefer commands over click handlers for ViewModel-driven actions. -* Keep command execution focused. -* Avoid putting large workflows directly inside command implementations. -* Keep `CanExecute` logic cheap. -* Refresh command availability only when relevant state changes. -* Avoid command implementations with hidden side effects. -* Handle async commands safely. -* Prevent accidental duplicate execution when an async action must not run concurrently. -* Never use `async void` except for true event handlers. - -## Async and Threading - -* Keep async operations asynchronous throughout the call chain. -* Avoid `.Result`, `.Wait()` and other synchronous blocking of async work. -* Do not block the UI thread. -* Run I/O asynchronously. -* Move expensive CPU work off the UI thread only when necessary. -* Marshal UI updates back to the UI thread when required. -* Keep Dispatcher usage minimal and explicit. -* Do not use the Dispatcher to hide incorrect threading design. -* Support `CancellationToken` for cancellable long-running operations. -* Cancel obsolete work when views or selections change. -* Prevent race conditions caused by overlapping async operations. -* Handle exceptions from background operations explicitly. - -## UI Thread - -* Treat the UI thread as a scarce resource. -* Avoid expensive loops, parsing, serialization, database access or network calls on the UI thread. -* Avoid excessive Dispatcher invocations. -* Batch UI updates where practical. -* Do not update UI-bound collections excessively in tight loops. -* Avoid synchronous waits on background work. -* Keep rendering-related callbacks lightweight. - -## Collections - -* Use `ObservableCollection` only when collection change notifications are required. -* Do not use `ObservableCollection` as a general-purpose collection. -* Use `List` or other suitable collections for non-observable internal data. -* Avoid replacing entire observable collections when incremental updates are sufficient. -* Avoid thousands of individual collection notifications when a bulk update is more appropriate. -* Keep collection mutations on the correct thread. -* Avoid exposing mutable internal collections unnecessarily. -* Prefer read-only views where consumers should not modify data. - -## XAML - -* Keep XAML readable and focused. -* Avoid excessively large view files. -* Split complex views into focused controls when it improves maintainability. -* Use resources for repeated values and styles. -* Avoid magic numbers in XAML. -* Keep styles and templates consistent. -* Avoid excessive inline styling. -* Prefer reusable resources over duplicated markup. -* Avoid deeply nested panels. -* Keep visual trees as shallow as practical. -* Use semantic control choices. -* Avoid unnecessary containers. -* Do not overuse triggers when simpler state representation is possible. -* Keep templates understandable. -* Avoid XAML tricks that make behavior hard to discover. - -## Layout - -* Prefer `Grid` for structured layouts. -* Use `StackPanel` only where its layout behavior is actually appropriate. -* Avoid unnecessary nested panels. -* Avoid fixed sizes unless the design requires them. -* Prefer responsive sizing with `Auto` and `*`. -* Avoid layout configurations that cause excessive measure/arrange passes. -* Be careful with large visual trees inside scrolling containers. -* Avoid disabling virtualization accidentally. - -## Virtualization - -* Keep UI virtualization enabled for large collections. -* Do not use container layouts that disable virtualization without a reason. -* Avoid wrapping large virtualized item lists in additional scrolling containers. -* Use virtualizing panels where appropriate. -* Verify virtualization when displaying large data sets. -* Avoid rendering thousands of controls simultaneously. -* Prefer paging, incremental loading or virtualization for very large data sets. - -## Resources and Styles - -* Use shared resources for repeated styles, brushes, templates and dimensions. -* Keep resource dictionaries focused. -* Avoid giant global resource dictionaries. -* Prefer feature-level resources when styles are not truly global. -* Use `StaticResource` by default. -* Use `DynamicResource` only when runtime resource replacement is required. -* Avoid excessive dynamic resource lookups. -* Keep theme resources separated from application logic. -* Avoid hardcoded colors and dimensions when design tokens or resources already exist. - -## Dependency Properties - -* Use dependency properties only when WPF property-system behavior is required. -* Do not use dependency properties as a replacement for normal CLR properties. -* Keep metadata and callbacks lightweight. -* Avoid expensive work in property-changed callbacks. -* Avoid callbacks with hidden side effects. -* Validate or coerce values only when the control contract requires it. -* Do not expose mutable default values in dependency property metadata. - -## Attached Properties and Behaviors - -* Use attached properties and behaviors for reusable view-specific behavior. -* Do not use them to hide business logic. -* Keep behaviors focused and predictable. -* Clean up event handlers when behaviors are detached. -* Avoid global attached-property state. -* Prefer explicit behavior over complex XAML hacks. - -## Events - -* Avoid unnecessary event subscriptions. -* Unsubscribe from long-lived publishers when required. -* Prevent memory leaks from event handlers. -* Prefer weak events where publisher lifetime significantly exceeds subscriber lifetime. -* Keep event handlers small. -* Do not use events as hidden global communication channels. -* Avoid excessive event chaining. - -## Memory Management - -* Watch for memory leaks caused by: - - * Event subscriptions - * Timers - * Static references - * Long-lived services - * Cached views - * Closures - * Collection views - * Binding-related references -* Dispose resources correctly. -* Stop timers and background work when no longer needed. -* Avoid retaining closed windows or unloaded views. -* Do not keep unnecessary references to visual elements. -* Profile memory when long-running applications continuously grow. - -## Windows and Dialogs - -* Keep window lifecycle explicit. -* Avoid creating duplicate windows unintentionally. -* Do not keep hidden windows alive without a reason. -* Separate dialog logic from business logic. -* Prefer dialog services when ViewModels need to request user interaction. -* Keep ownership relationships explicit. -* Avoid application shutdown behavior that depends on accidental window lifetime. - -## Navigation - -* Keep navigation state explicit. -* Avoid coupling ViewModels directly to concrete views. -* Avoid service locator patterns for view resolution. -* Keep navigation history intentional. -* Dispose or release navigation targets when they are no longer required. -* Do not retain entire navigation graphs unnecessarily. - -## Validation - -* Validate user input at the appropriate boundary. -* Keep validation logic out of XAML when it becomes complex. -* Prefer reusable validation rules or ViewModel validation for non-trivial cases. -* Display validation errors consistently. -* Do not rely on UI validation as a security boundary. -* Validate again at backend or domain boundaries when required. -* Preserve user input on recoverable errors. - -## Performance - -* Keep the UI thread responsive. -* Minimize visual tree depth. -* Keep virtualization enabled. -* Avoid unnecessary bindings. -* Avoid unnecessary converters. -* Avoid unnecessary resource lookups. -* Avoid unnecessary property change notifications. -* Avoid frequent full collection refreshes. -* Avoid loading large datasets eagerly. -* Avoid loading large images at full resolution when unnecessary. -* Freeze `Freezable` objects where practical. -* Reuse immutable resources where appropriate. -* Avoid unnecessary animations. -* Avoid high-frequency timers on the UI thread. -* Measure startup time, UI responsiveness, memory usage and rendering performance before micro-optimizing. - -## Images and Media - -* Load images at an appropriate resolution. -* Avoid decoding images significantly larger than their displayed size. -* Release streams and file handles correctly. -* Avoid locking image files unintentionally. -* Cache images only when there is a clear memory strategy. -* Avoid keeping large bitmaps alive unnecessarily. -* Prefer frozen image resources when they are immutable. - -## Security - -* Treat all external input as untrusted. -* Never expose secrets, credentials or tokens in UI code. -* Do not store secrets in configuration files committed to source control. -* Avoid leaking sensitive information through logs, dialogs or exception messages. -* Validate file paths and external resources. -* Do not execute external processes or files without explicit validation. -* Avoid insecure deserialization. -* Do not weaken TLS, authentication or certificate validation. -* Prefer secure defaults. -* Never disable security controls for convenience. - -## File and Process Access - -* Validate file paths before use. -* Avoid assuming files or directories exist. -* Handle permissions and locked files gracefully. -* Avoid arbitrary shell execution. -* Quote and validate process arguments safely. -* Do not concatenate untrusted input into shell commands. -* Avoid elevated privileges unless explicitly required. -* Clean up temporary files when appropriate. - -## Error Handling - -* Handle expected errors explicitly. -* Do not swallow exceptions. -* Preserve useful exception context. -* Avoid showing raw technical exceptions directly to end users. -* Log enough information for diagnosis without exposing sensitive data. -* Keep user-facing error messages clear and actionable. -* Avoid using exceptions for normal control flow. -* Ensure background exceptions are observed. - -## Logging - -* Use structured logging. -* Avoid excessive logging on the UI thread. -* Do not log every property change or binding update. -* Never log secrets, tokens, credentials or sensitive user data. -* Include relevant context for operational failures. -* Avoid logging the same exception repeatedly at multiple layers. - -## Architecture - -* Keep presentation, application, domain and infrastructure concerns separated. -* Avoid direct database access from views or ViewModels. -* Avoid direct HTTP access from controls. -* Keep external integrations behind focused services. -* Avoid circular dependencies. -* Keep feature boundaries clear. -* Do not create shared utility classes for unrelated functionality. -* Keep shared code genuinely reusable. -* Minimize global state. -* Avoid static service access. - -## Dependency Injection - -* Use dependency injection where lifecycle management, substitution or testability benefits from it. -* Avoid service locator patterns. -* Keep constructor dependencies minimal. -* Do not inject dependencies that are not used. -* Choose service lifetimes intentionally. -* Do not make stateful services global without a concrete reason. -* Avoid introducing interfaces solely for dependency injection when no abstraction is needed. - -## Testing - -* Keep ViewModels testable without a UI thread where practical. -* Test behavior rather than implementation details. -* Test domain and application logic independently from WPF. -* Avoid brittle tests coupled to XAML structure. -* Keep UI automation tests focused on critical flows. -* Mock external boundaries rather than internal details. -* Keep tests deterministic. -* Avoid real network, database or filesystem dependencies in unit tests unless explicitly intended. - -## Code Quality - -* Use nullable reference types. -* Prefer modern, readable C# syntax. -* Avoid unnecessary interfaces and abstractions. -* Prefer concrete types where no abstraction is required. -* Use descriptive names. -* Remove dead code. -* Remove commented-out code. -* Do not add comments unless the user explicitly requests them. -* Treat compiler, analyzer and binding warnings seriously. -* Do not suppress warnings without a concrete reason. -* Prefer correctness, responsiveness, security and maintainability over cleverness. - -## Performance Priority - -Prioritize WPF performance work in this order: - -* UI architecture -* UI thread blocking -* Data loading and I/O -* Virtualization -* Visual tree complexity -* Binding and notification frequency -* Rendering and images -* Memory retention and leaks -* Allocations -* CPU micro-optimizations - -Never optimize based purely on assumptions. - -## Safety Rule - -* The UI must remain responsive. -* Do not block the UI thread with I/O or expensive CPU work. -* Do not bypass validation or security controls for convenience. -* Do not introduce hidden cross-thread access. -* Prefer predictable, explicit and testable UI behavior. diff --git a/shared/rules/wpf/index.md b/shared/rules/wpf/index.md new file mode 100644 index 0000000..59a49fe --- /dev/null +++ b/shared/rules/wpf/index.md @@ -0,0 +1,34 @@ +# WPF Code Guidelines + +* Use modern C# and current .NET/WPF conventions. +* Keep UI, application logic and domain logic clearly separated. +* Prefer MVVM for non-trivial views. +* Keep code-behind minimal. +* Use code-behind only for view-specific behavior that does not belong in the ViewModel. +* Avoid business logic in views. +* Avoid direct service access from controls. +* Keep dependencies explicit and testable. +* Prefer composition over inheritance. +* Avoid unnecessary abstractions and framework wrappers. +* Follow the existing project architecture unless there is a strong reason to change it. + +## Safety Rule + +* The UI must remain responsive. +* Do not block the UI thread with I/O or expensive CPU work. +* Do not bypass validation or security controls for convenience. +* Do not introduce hidden cross-thread access. +* Prefer predictable, explicit and testable UI behavior. + +## Detailed guidance + +Read the matching reference file before working in that area: + +| Read this reference for... | ...this kind of work | +| --- | --- | +| `references/mvvm-and-binding.md` | MVVM, data binding, property change notifications, dependency/attached properties | +| `references/commands-and-async.md` | Commands, async/threading, UI-thread work, events | +| `references/collections-and-xaml.md` | Collections, virtualization, layout, XAML | +| `references/resources-and-lifecycle.md` | Resources/styles, windows/dialogs, navigation, memory, images/media | +| `references/security-and-errors.md` | Security, file/process access, error handling, logging, validation | +| `references/architecture-and-quality.md` | Architecture, DI, testing, code quality, performance | diff --git a/shared/rules/wpf/references/architecture-and-quality.md b/shared/rules/wpf/references/architecture-and-quality.md new file mode 100644 index 0000000..1f6d588 --- /dev/null +++ b/shared/rules/wpf/references/architecture-and-quality.md @@ -0,0 +1,82 @@ +## Architecture + +* Keep presentation, application, domain and infrastructure concerns separated. +* Avoid direct database access from views or ViewModels. +* Avoid direct HTTP access from controls. +* Keep external integrations behind focused services. +* Avoid circular dependencies. +* Keep feature boundaries clear. +* Do not create shared utility classes for unrelated functionality. +* Keep shared code genuinely reusable. +* Minimize global state. +* Avoid static service access. + +## Dependency Injection + +* Use dependency injection where lifecycle management, substitution or testability benefits from it. +* Avoid service locator patterns. +* Keep constructor dependencies minimal. +* Do not inject dependencies that are not used. +* Choose service lifetimes intentionally. +* Do not make stateful services global without a concrete reason. +* Avoid introducing interfaces solely for dependency injection when no abstraction is needed. + +## Testing + +* Keep ViewModels testable without a UI thread where practical. +* Test behavior rather than implementation details. +* Test domain and application logic independently from WPF. +* Avoid brittle tests coupled to XAML structure. +* Keep UI automation tests focused on critical flows. +* Mock external boundaries rather than internal details. +* Keep tests deterministic. +* Avoid real network, database or filesystem dependencies in unit tests unless explicitly intended. + +## Code Quality + +* Use nullable reference types. +* Prefer modern, readable C# syntax. +* Avoid unnecessary interfaces and abstractions. +* Prefer concrete types where no abstraction is required. +* Use descriptive names. +* Remove dead code. +* Remove commented-out code. +* Do not add comments unless the user explicitly requests them. +* Treat compiler, analyzer and binding warnings seriously. +* Do not suppress warnings without a concrete reason. +* Prefer correctness, responsiveness, security and maintainability over cleverness. + +## Performance + +* Keep the UI thread responsive. +* Minimize visual tree depth. +* Keep virtualization enabled. +* Avoid unnecessary bindings. +* Avoid unnecessary converters. +* Avoid unnecessary resource lookups. +* Avoid unnecessary property change notifications. +* Avoid frequent full collection refreshes. +* Avoid loading large datasets eagerly. +* Avoid loading large images at full resolution when unnecessary. +* Freeze `Freezable` objects where practical. +* Reuse immutable resources where appropriate. +* Avoid unnecessary animations. +* Avoid high-frequency timers on the UI thread. +* Measure startup time, UI responsiveness, memory usage and rendering performance before micro-optimizing. + +## Performance Priority + +Prioritize WPF performance work in this order: + +* UI architecture +* UI thread blocking +* Data loading and I/O +* Virtualization +* Visual tree complexity +* Binding and notification frequency +* Rendering and images +* Memory retention and leaks +* Allocations +* CPU micro-optimizations + +Never optimize based purely on assumptions. diff --git a/shared/rules/wpf/references/collections-and-xaml.md b/shared/rules/wpf/references/collections-and-xaml.md new file mode 100644 index 0000000..b4ef5ba --- /dev/null +++ b/shared/rules/wpf/references/collections-and-xaml.md @@ -0,0 +1,49 @@ +## Collections + +* Use `ObservableCollection` only when collection change notifications are required. +* Do not use `ObservableCollection` as a general-purpose collection. +* Use `List` or other suitable collections for non-observable internal data. +* Avoid replacing entire observable collections when incremental updates are sufficient. +* Avoid thousands of individual collection notifications when a bulk update is more appropriate. +* Keep collection mutations on the correct thread. +* Avoid exposing mutable internal collections unnecessarily. +* Prefer read-only views where consumers should not modify data. + +## XAML + +* Keep XAML readable and focused. +* Avoid excessively large view files. +* Split complex views into focused controls when it improves maintainability. +* Use resources for repeated values and styles. +* Avoid magic numbers in XAML. +* Keep styles and templates consistent. +* Avoid excessive inline styling. +* Prefer reusable resources over duplicated markup. +* Avoid deeply nested panels. +* Keep visual trees as shallow as practical. +* Use semantic control choices. +* Avoid unnecessary containers. +* Do not overuse triggers when simpler state representation is possible. +* Keep templates understandable. +* Avoid XAML tricks that make behavior hard to discover. + +## Layout + +* Prefer `Grid` for structured layouts. +* Use `StackPanel` only where its layout behavior is actually appropriate. +* Avoid unnecessary nested panels. +* Avoid fixed sizes unless the design requires them. +* Prefer responsive sizing with `Auto` and `*`. +* Avoid layout configurations that cause excessive measure/arrange passes. +* Be careful with large visual trees inside scrolling containers. +* Avoid disabling virtualization accidentally. + +## Virtualization + +* Keep UI virtualization enabled for large collections. +* Do not use container layouts that disable virtualization without a reason. +* Avoid wrapping large virtualized item lists in additional scrolling containers. +* Use virtualizing panels where appropriate. +* Verify virtualization when displaying large data sets. +* Avoid rendering thousands of controls simultaneously. +* Prefer paging, incremental loading or virtualization for very large data sets. diff --git a/shared/rules/wpf/references/commands-and-async.md b/shared/rules/wpf/references/commands-and-async.md new file mode 100644 index 0000000..5a51164 --- /dev/null +++ b/shared/rules/wpf/references/commands-and-async.md @@ -0,0 +1,46 @@ +## Commands + +* Prefer commands over click handlers for ViewModel-driven actions. +* Keep command execution focused. +* Avoid putting large workflows directly inside command implementations. +* Keep `CanExecute` logic cheap. +* Refresh command availability only when relevant state changes. +* Avoid command implementations with hidden side effects. +* Handle async commands safely. +* Prevent accidental duplicate execution when an async action must not run concurrently. +* Never use `async void` except for true event handlers. + +## Async and Threading + +* Keep async operations asynchronous throughout the call chain. +* Avoid `.Result`, `.Wait()` and other synchronous blocking of async work. +* Do not block the UI thread. +* Run I/O asynchronously. +* Move expensive CPU work off the UI thread only when necessary. +* Marshal UI updates back to the UI thread when required. +* Keep Dispatcher usage minimal and explicit. +* Do not use the Dispatcher to hide incorrect threading design. +* Support `CancellationToken` for cancellable long-running operations. +* Cancel obsolete work when views or selections change. +* Prevent race conditions caused by overlapping async operations. +* Handle exceptions from background operations explicitly. + +## UI Thread + +* Treat the UI thread as a scarce resource. +* Avoid expensive loops, parsing, serialization, database access or network calls on the UI thread. +* Avoid excessive Dispatcher invocations. +* Batch UI updates where practical. +* Do not update UI-bound collections excessively in tight loops. +* Avoid synchronous waits on background work. +* Keep rendering-related callbacks lightweight. + +## Events + +* Avoid unnecessary event subscriptions. +* Unsubscribe from long-lived publishers when required. +* Prevent memory leaks from event handlers. +* Prefer weak events where publisher lifetime significantly exceeds subscriber lifetime. +* Keep event handlers small. +* Do not use events as hidden global communication channels. +* Avoid excessive event chaining. diff --git a/shared/rules/wpf/references/mvvm-and-binding.md b/shared/rules/wpf/references/mvvm-and-binding.md new file mode 100644 index 0000000..77eeff2 --- /dev/null +++ b/shared/rules/wpf/references/mvvm-and-binding.md @@ -0,0 +1,60 @@ +## MVVM + +* Keep ViewModels focused on presentation state and commands. +* Do not put UI element references into ViewModels. +* Do not access `Window`, `UserControl`, `DispatcherObject` or visual tree elements from ViewModels. +* Avoid direct navigation, dialogs or message boxes from ViewModels without an abstraction when testability matters. +* Prefer explicit application services for navigation, dialogs and external interactions. +* Keep domain logic outside ViewModels. +* Do not use ViewModels as general-purpose service containers. +* Keep ViewModel dependencies minimal. +* Prefer immutable or readonly state where practical. +* Avoid duplicated derived state. +* Keep state transitions predictable. + +## Data Binding + +* Prefer data binding over manual UI synchronization. +* Use strongly typed properties. +* Use appropriate binding modes. +* Prefer `OneWay` when two-way updates are not required. +* Use `TwoWay` only when the UI must modify the source. +* Avoid unnecessary `UpdateSourceTrigger=PropertyChanged` for expensive operations. +* Keep binding paths simple and stable. +* Avoid deeply nested binding paths. +* Do not hide broken bindings. +* Treat binding errors as real defects. +* Use `FallbackValue` and `TargetNullValue` only when they reflect intended behavior. +* Avoid excessive converters. +* Prefer exposing correctly shaped state from the ViewModel over complex converter logic. +* Avoid `MultiBinding` when simpler state modeling is clearer. +* Do not put business logic into converters. + +## Property Change Notifications + +* Implement property change notifications consistently. +* Avoid raising `PropertyChanged` unnecessarily. +* Raise notifications only when values actually change. +* Keep dependent property notifications explicit. +* Avoid hidden notification chains that are difficult to reason about. +* Prefer reusable base implementations only when they reduce duplication without obscuring behavior. +* Do not use reflection-based notification mechanisms unless there is a concrete benefit. + +## Dependency Properties + +* Use dependency properties only when WPF property-system behavior is required. +* Do not use dependency properties as a replacement for normal CLR properties. +* Keep metadata and callbacks lightweight. +* Avoid expensive work in property-changed callbacks. +* Avoid callbacks with hidden side effects. +* Validate or coerce values only when the control contract requires it. +* Do not expose mutable default values in dependency property metadata. + +## Attached Properties and Behaviors + +* Use attached properties and behaviors for reusable view-specific behavior. +* Do not use them to hide business logic. +* Keep behaviors focused and predictable. +* Clean up event handlers when behaviors are detached. +* Avoid global attached-property state. +* Prefer explicit behavior over complex XAML hacks. diff --git a/shared/rules/wpf/references/resources-and-lifecycle.md b/shared/rules/wpf/references/resources-and-lifecycle.md new file mode 100644 index 0000000..f09dc96 --- /dev/null +++ b/shared/rules/wpf/references/resources-and-lifecycle.md @@ -0,0 +1,58 @@ +## Resources and Styles + +* Use shared resources for repeated styles, brushes, templates and dimensions. +* Keep resource dictionaries focused. +* Avoid giant global resource dictionaries. +* Prefer feature-level resources when styles are not truly global. +* Use `StaticResource` by default. +* Use `DynamicResource` only when runtime resource replacement is required. +* Avoid excessive dynamic resource lookups. +* Keep theme resources separated from application logic. +* Avoid hardcoded colors and dimensions when design tokens or resources already exist. + +## Windows and Dialogs + +* Keep window lifecycle explicit. +* Avoid creating duplicate windows unintentionally. +* Do not keep hidden windows alive without a reason. +* Separate dialog logic from business logic. +* Prefer dialog services when ViewModels need to request user interaction. +* Keep ownership relationships explicit. +* Avoid application shutdown behavior that depends on accidental window lifetime. + +## Navigation + +* Keep navigation state explicit. +* Avoid coupling ViewModels directly to concrete views. +* Avoid service locator patterns for view resolution. +* Keep navigation history intentional. +* Dispose or release navigation targets when they are no longer required. +* Do not retain entire navigation graphs unnecessarily. + +## Memory Management + +* Watch for memory leaks caused by: + + * Event subscriptions + * Timers + * Static references + * Long-lived services + * Cached views + * Closures + * Collection views + * Binding-related references +* Dispose resources correctly. +* Stop timers and background work when no longer needed. +* Avoid retaining closed windows or unloaded views. +* Do not keep unnecessary references to visual elements. +* Profile memory when long-running applications continuously grow. + +## Images and Media + +* Load images at an appropriate resolution. +* Avoid decoding images significantly larger than their displayed size. +* Release streams and file handles correctly. +* Avoid locking image files unintentionally. +* Cache images only when there is a clear memory strategy. +* Avoid keeping large bitmaps alive unnecessarily. +* Prefer frozen image resources when they are immutable. diff --git a/shared/rules/wpf/references/security-and-errors.md b/shared/rules/wpf/references/security-and-errors.md new file mode 100644 index 0000000..3a95fc1 --- /dev/null +++ b/shared/rules/wpf/references/security-and-errors.md @@ -0,0 +1,53 @@ +## Security + +* Treat all external input as untrusted. +* Never expose secrets, credentials or tokens in UI code. +* Do not store secrets in configuration files committed to source control. +* Avoid leaking sensitive information through logs, dialogs or exception messages. +* Validate file paths and external resources. +* Do not execute external processes or files without explicit validation. +* Avoid insecure deserialization. +* Do not weaken TLS, authentication or certificate validation. +* Prefer secure defaults. +* Never disable security controls for convenience. + +## File and Process Access + +* Validate file paths before use. +* Avoid assuming files or directories exist. +* Handle permissions and locked files gracefully. +* Avoid arbitrary shell execution. +* Quote and validate process arguments safely. +* Do not concatenate untrusted input into shell commands. +* Avoid elevated privileges unless explicitly required. +* Clean up temporary files when appropriate. + +## Error Handling + +* Handle expected errors explicitly. +* Do not swallow exceptions. +* Preserve useful exception context. +* Avoid showing raw technical exceptions directly to end users. +* Log enough information for diagnosis without exposing sensitive data. +* Keep user-facing error messages clear and actionable. +* Avoid using exceptions for normal control flow. +* Ensure background exceptions are observed. + +## Logging + +* Use structured logging. +* Avoid excessive logging on the UI thread. +* Do not log every property change or binding update. +* Never log secrets, tokens, credentials or sensitive user data. +* Include relevant context for operational failures. +* Avoid logging the same exception repeatedly at multiple layers. + +## Validation + +* Validate user input at the appropriate boundary. +* Keep validation logic out of XAML when it becomes complex. +* Prefer reusable validation rules or ViewModel validation for non-trivial cases. +* Display validation errors consistently. +* Do not rely on UI validation as a security boundary. +* Validate again at backend or domain boundaries when required. +* Preserve user input on recoverable errors.