61 lines
4.1 KiB
Markdown
61 lines
4.1 KiB
Markdown
---
|
||
source_files:
|
||
- Common/DTS.Common/Classes/DTS.Viewer/Commands/RelayCommand.cs
|
||
generated_at: "2026-04-16T03:19:06.518329+00:00"
|
||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||
schema_version: 1
|
||
sha256: "33db5b96b73a6f00"
|
||
---
|
||
|
||
# Commands
|
||
|
||
### 1. **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 supports optional conditional execution via a `CanExecute` predicate and integrates with WPF’s `CommandManager` to automatically re-evaluate command availability when UI state changes (e.g., focus or selection changes). Its role is to serve as a lightweight, standard command implementation for MVVM pattern adoption, avoiding boilerplate command classes per action.
|
||
|
||
---
|
||
|
||
### 2. **Public Interface**
|
||
- **`RelayCommand(Action<object> execute)`**
|
||
Constructor. Initializes the command with an execution delegate and no `CanExecute` predicate (i.e., always executable).
|
||
- Throws `ArgumentNullException` if `execute` is `null`.
|
||
|
||
- **`RelayCommand(Action<object> execute, Predicate<object> canExecute)`**
|
||
Constructor. Initializes the command with both execution and availability predicates.
|
||
- Throws `ArgumentNullException` if `execute` is `null`.
|
||
- `canExecute` may be `null`, in which case the command is always executable.
|
||
|
||
- **`bool CanExecute(object parameter)`**
|
||
Implements `ICommand.CanExecute`. Returns `true` if `_canExecute` is `null` or if `_canExecute(parameter)` returns `true`; otherwise `false`.
|
||
|
||
- **`event EventHandler CanExecuteChanged`**
|
||
Implements `ICommand.CanExecuteChanged`. Subscribes/unsubscribes to `CommandManager.RequerySuggested`, triggering WPF to re-query `CanExecute` when system events (e.g., keyboard/mouse input, focus changes) occur.
|
||
|
||
- **`void Execute(object parameter)`**
|
||
Implements `ICommand.Execute`. Invokes `_execute(parameter)`. No validation or exception handling is performed; exceptions propagate to the caller.
|
||
|
||
---
|
||
|
||
### 3. **Invariants**
|
||
- `_execute` is **never `null`** after construction (enforced via `ArgumentNullException` in both constructors).
|
||
- `_canExecute` may be `null`; in this case, `CanExecute` always returns `true`.
|
||
- `CanExecuteChanged` events are **always** routed to `CommandManager.RequerySuggested`; no custom event storage is used.
|
||
- `Execute` and `CanExecute` are called with the same `parameter` value provided by the command source (e.g., `Button.CommandParameter`).
|
||
|
||
---
|
||
|
||
### 4. **Dependencies**
|
||
- **Dependencies on external modules**:
|
||
- `System` (for `Action<T>`, `Predicate<T>`, `ArgumentNullException`)
|
||
- `System.Windows.Input` (for `ICommand`, `CommandManager`)
|
||
- **Dependencies on other modules in the codebase**: None (no internal `using` statements beyond standard libraries).
|
||
- **Depended upon by**: Presumably UI components (e.g., `Button`, `MenuItem`) in WPF views that bind commands via MVVM. Not visible in this file, but inferred from `ICommand` usage.
|
||
|
||
---
|
||
|
||
### 5. **Gotchas**
|
||
- **No manual `CanExecuteChanged` raising**: Since `CanExecuteChanged` is wired to `CommandManager.RequerySuggested`, the command’s executability is only re-evaluated on `CommandManager`-triggered events (e.g., user input). If the command’s availability depends on non-UI state (e.g., background task completion), `CommandManager.InvalidateRequerySuggested()` must be called externally to force re-evaluation.
|
||
- **No parameter validation**: `Execute` passes the `parameter` directly to `_execute` without null-checking or type validation. If `_execute` expects a specific type (e.g., `string`), passing an incompatible type will cause a runtime exception.
|
||
- **Thread affinity**: `Execute` runs on the calling thread (typically the UI thread), but no thread-safety guarantees are provided. If invoked from a background thread, UI updates inside `_execute` will fail.
|
||
- **Memory leak risk**: If subscribers to `CanExecuteChanged` are not properly disposed, the `CommandManager` may hold references indefinitely (though this is a general WPF pattern risk, not unique to this class).
|
||
|
||
None identified beyond the above. |