- Implement `INotifyPropertyChanged` using `[CallerMemberName]` so property setters notify the UI without hardcoding string names — hardcoded strings break silently on rename: `protected void OnPropertyChanged([CallerMemberName] string name = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));`
- Bind buttons and triggers to `ICommand` properties (use `RelayCommand` from CommunityToolkit.Mvvm) rather than code-behind event handlers — keeps all logic in the ViewModel and testable without a UI: `public ICommand SaveCommand { get; } = new RelayCommand(ExecuteSave, CanSave);`
- Use `ObservableCollection<T>` for all list properties displayed by the UI — plain `List<T>` does not implement `INotifyCollectionChanged`, so adding or removing items never updates bound controls at runtime.
- Never access or mutate UI elements from a background thread — use `await Task.Run(...)` from an `async` method to run work off-thread, then update ViewModel properties after the `await`; WPF's synchronization context marshals the continuation back automatically.
- Define reusable styles, brushes, and data templates in `ResourceDictionary` files merged into `App.xaml` — use `x:Key` for targeted application and `TargetType` without a key for implicit type-wide application; never duplicate `Style` definitions inline across multiple `UserControl` files.
- Use `CollectionViewSource` in XAML or `ICollectionView` in the ViewModel for sorting and filtering — never mutate the backing `ObservableCollection` for display concerns, as that couples data to presentation.