--- source_files: - Common/DTS.CommonCore/Classes/DTS.Viewer/Commands/RelayCommand.cs generated_at: "2026-04-16T02:42:33.604683+00:00" model: "Qwen/Qwen3-Coder-Next-FP8" schema_version: 1 sha256: "63672ade54ed35d0" --- # Commands ### **Purpose** This module implements a concrete, reusable `ICommand`-based command class (`RelayCommand`) for WPF applications, enabling decoupling of UI actions (e.g., button clicks) from their execution logic. It serves as a lightweight command adapter that forwards `Execute` and `CanExecute` calls to user-provided delegates, supporting both mandatory execution logic and optional, parameterized execution guards. This pattern is foundational for implementing MVVM-style command binding in WPF. --- ### **Public Interface** All members are public and part of the `RelayCommand` class. - **`RelayCommand(Action execute)`** Constructor. Initializes the command with an execution delegate and no `CanExecute` guard (i.e., `CanExecute` always returns `true`). Throws `ArgumentNullException` if `execute` is `null`. - **`RelayCommand(Action execute, Predicate canExecute)`** Constructor. Initializes the command with both execution and guard delegates. Throws `ArgumentNullException` if `execute` is `null`. The `canExecute` parameter may be `null`, in which case `CanExecute` defaults to `true`. - **`bool CanExecute(object parameter)`** Implements `ICommand.CanExecute`. Invokes the stored `_canExecute` predicate (if non-null) with `parameter`; otherwise returns `true`. - **`void Execute(object parameter)`** Implements `ICommand.Execute`. Invokes the stored `_execute` action with `parameter`. No validation is performed on `parameter` beyond null-safety of the delegate itself. - **`event EventHandler CanExecuteChanged`** Implements `ICommand.CanExecuteChanged`. Subscribes/unsubscribes to `CommandManager.RequerySuggested`, enabling automatic re-evaluation of `CanExecute` when WPF detects relevant state changes (e.g., keyboard/mouse input, focus changes). --- ### **Invariants** - `_execute` is **never null** after construction (enforced via `ArgumentNullException` in both constructors). - `_canExecute` may be `null`; if so, `CanExecute` always returns `true`. - `CanExecuteChanged` event handlers are **always** attached to `CommandManager.RequerySuggested`, ensuring WPF’s command system triggers requery logic. - No explicit validation is performed on the `parameter` passed to `Execute` or `CanExecute`; nulls are passed directly to the delegates. --- ### **Dependencies** - **External Dependencies**: - `System` (for `Action`, `Predicate`, `ArgumentNullException`) - `System.Windows.Input` (for `ICommand`, `CommandManager`) - **Internal Dependencies**: - No other modules in the codebase are referenced (self-contained). - **Depended Upon**: - Likely consumed by WPF UI layers (e.g., `Button.Command` bindings) and view models throughout the `DTS.Viewer` subsystem. --- ### **Gotchas** - **No manual `CanExecuteChanged` raising**: The class relies solely on `CommandManager.RequerySuggested` to trigger `CanExecute` re-evaluation. If the command’s executability depends on non-UI state changes (e.g., background thread updates), callers must manually invoke `CommandManager.InvalidateRequerySuggested()` (or similar) to force updates. - **Parameter handling**: The `parameter` passed to `Execute`/`CanExecute` is unvalidated. Passing `null` is permitted and will be forwarded to the delegates—consumers must handle `null` parameters explicitly if needed. - **Thread affinity**: `CommandManager.RequerySuggested` is raised on the UI thread. If `CanExecute` delegates access non-UI-thread resources, thread-safety must be ensured by the caller. - **No disposal pattern**: The class does not implement `IDisposable`, and event subscriptions (via `CanExecuteChanged`) are not explicitly cleaned up—relying on WPF’s lifetime management. This is acceptable for typical view model lifetimes but may cause leaks in long-lived command instances. - **No async support**: `Execute` is synchronous; asynchronous operations require manual wrapping (e.g., `async void` or fire-and-forget), which is error-prone.