first commit
This commit is contained in:
@@ -0,0 +1,382 @@
|
||||
# MVVM Pattern Implementation
|
||||
|
||||
<cite>
|
||||
**Referenced Files in This Document**
|
||||
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
|
||||
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
|
||||
- [MainWindow.axaml](file://ClassicAssist.Avalonia/Views/MainWindow.axaml)
|
||||
- [MainWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/MainWindow.axaml.cs)
|
||||
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
|
||||
- [Program.cs](file://ClassicAssist.Avalonia/Program.cs)
|
||||
- [DialogWindowViewModel.cs](file://ClassicAssist.Avalonia/ViewModels/DialogWindowViewModel.cs)
|
||||
- [DialogWindow.axaml](file://ClassicAssist.Avalonia/Views/DialogWindow.axaml)
|
||||
- [DialogWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/DialogWindow.axaml.cs)
|
||||
- [GeneralControlViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/GeneralControlViewModel.cs)
|
||||
- [GeneralControl.axaml](file://ClassicAssist.Avalonia/Views/GeneralControl.axaml)
|
||||
- [GeneralControl.axaml.cs](file://ClassicAssist.Avalonia/Views/GeneralControl.axaml.cs)
|
||||
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
|
||||
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
|
||||
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
|
||||
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
|
||||
</cite>
|
||||
|
||||
## Table of Contents
|
||||
1. [Introduction](#introduction)
|
||||
2. [Project Structure](#project-structure)
|
||||
3. [Core Components](#core-components)
|
||||
4. [Architecture Overview](#architecture-overview)
|
||||
5. [Detailed Component Analysis](#detailed-component-analysis)
|
||||
6. [Dependency Analysis](#dependency-analysis)
|
||||
7. [Performance Considerations](#performance-considerations)
|
||||
8. [Troubleshooting Guide](#troubleshooting-guide)
|
||||
9. [Conclusion](#conclusion)
|
||||
|
||||
## Introduction
|
||||
This document explains how the Model-View-ViewModel (MVVM) pattern is implemented in ClassicAssist.Avalonia. It focuses on separation of concerns between Views (AXAML), ViewModels (C# classes), and Models (business logic), with emphasis on:
|
||||
- The BaseViewModel that provides common functionality such as property change notification and command binding
|
||||
- Data binding mechanisms and event handling patterns
|
||||
- Lifecycle management of ViewModels
|
||||
- Concrete examples from MainWindow and other key views
|
||||
- Testing strategies for ViewModels and best practices to maintain clean separation between presentation logic and business rules
|
||||
|
||||
## Project Structure
|
||||
The Avalonia UI layer follows a clear folder structure aligned with MVVM:
|
||||
- Views are defined in AXAML files under ClassicAssist.Avalonia/Views, with code-behind files (.axaml.cs) kept minimal
|
||||
- ViewModels live in ClassicAssist.Shared/UI/ViewModels and implement presentation logic and data binding
|
||||
- Models and shared services reside in ClassicAssist.Shared, including UI infrastructure like dispatchers and UI invokers
|
||||
- App initialization wires up the root ViewModel and ensures UI updates occur on the correct thread
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "Avalonia UI Layer"
|
||||
A_MainWindow["MainWindow.axaml<br/>Code-behind: MainWindow.axaml.cs"]
|
||||
A_GeneralControl["GeneralControl.axaml<br/>Code-behind: GeneralControl.axaml.cs"]
|
||||
A_DialogWindow["DialogWindow.axaml<br/>Code-behind: DialogWindow.axaml.cs"]
|
||||
end
|
||||
subgraph "Shared UI Infrastructure"
|
||||
B_BaseViewModel["BaseViewModel.cs"]
|
||||
B_IDispatcher["IDispatcher.cs"]
|
||||
B_IUIInvoker["IUIInvoker.cs"]
|
||||
B_AvaloniaDispatcher["AvaloniaDispatcher.cs"]
|
||||
B_AvaloniaUIInvoker["AvaloniaUIInvoker.cs"]
|
||||
end
|
||||
subgraph "Shared Business Logic"
|
||||
C_Models["Models and Managers<br/>(ClassicAssist.Shared/Data/*)"]
|
||||
end
|
||||
A_MainWindow --> B_BaseViewModel
|
||||
A_GeneralControl --> B_BaseViewModel
|
||||
A_DialogWindow --> B_BaseViewModel
|
||||
B_BaseViewModel --> B_IDispatcher
|
||||
B_BaseViewModel --> B_IUIInvoker
|
||||
B_AvaloniaDispatcher --> B_IDispatcher
|
||||
B_AvaloniaUIInvoker --> B_IUIInvoker
|
||||
A_MainWindow --> C_Models
|
||||
A_GeneralControl --> C_Models
|
||||
A_DialogWindow --> C_Models
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [MainWindow.axaml](file://ClassicAssist.Avalonia/Views/MainWindow.axaml)
|
||||
- [MainWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/MainWindow.axaml.cs)
|
||||
- [GeneralControl.axaml](file://ClassicAssist.Avalonia/Views/GeneralControl.axaml)
|
||||
- [GeneralControl.axaml.cs](file://ClassicAssist.Avalonia/Views/GeneralControl.axaml.cs)
|
||||
- [DialogWindow.axaml](file://ClassicAssist.Avalonia/Views/DialogWindow.axaml)
|
||||
- [DialogWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/DialogWindow.axaml.cs)
|
||||
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
|
||||
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
|
||||
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
|
||||
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
|
||||
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
|
||||
|
||||
**Section sources**
|
||||
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
|
||||
- [Program.cs](file://ClassicAssist.Avalonia/Program.cs)
|
||||
|
||||
## Core Components
|
||||
- BaseViewModel: Provides common MVVM utilities such as property change notification and command support. All ViewModels inherit from this base to ensure consistent behavior and reduce boilerplate.
|
||||
- MainWindowViewModel: Root ViewModel for the main window; orchestrates UI state and delegates business operations to models/managers.
|
||||
- DialogWindowViewModel: Lightweight ViewModel used by modal dialogs to expose properties and commands bound from AXAML.
|
||||
- GeneralControlViewModel: Example of a reusable control ViewModel demonstrating encapsulated presentation logic.
|
||||
- Dispatcher and UI Invoker abstractions: Ensure UI updates occur on the UI thread regardless of background work.
|
||||
|
||||
Key responsibilities:
|
||||
- Views (AXAML): Define layout, styling, and declarative bindings to ViewModel properties and commands. Code-behind should remain thin and avoid business logic.
|
||||
- ViewModels: Expose bindable properties and commands, handle user interactions, coordinate with models, and update UI state safely via dispatcher/invoker.
|
||||
- Models: Contain business rules, data access, and domain logic. They do not depend on UI frameworks.
|
||||
|
||||
**Section sources**
|
||||
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
|
||||
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
|
||||
- [DialogWindowViewModel.cs](file://ClassicAssist.Avalonia/ViewModels/DialogWindowViewModel.cs)
|
||||
- [GeneralControlViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/GeneralControlViewModel.cs)
|
||||
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
|
||||
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
|
||||
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
|
||||
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
|
||||
|
||||
## Architecture Overview
|
||||
At runtime, the application initializes the UI framework, creates the root ViewModel, and sets it as the DataContext for the main view. ViewModels use the dispatcher to marshal UI updates onto the UI thread and invoke UI helpers through the UI invoker abstraction.
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant App as "App.axaml.cs"
|
||||
participant Program as "Program.cs"
|
||||
participant MainWindow as "MainWindow.axaml"
|
||||
participant VM as "MainWindowViewModel"
|
||||
participant Dispatcher as "AvaloniaDispatcher"
|
||||
participant UIInvoker as "AvaloniaUIInvoker"
|
||||
Program->>App : Initialize UI framework
|
||||
App->>MainWindow : Create main window
|
||||
App->>VM : Instantiate root ViewModel
|
||||
App->>MainWindow : Set DataContext = VM
|
||||
MainWindow-->>VM : Bindings resolve properties/commands
|
||||
VM->>Dispatcher : ExecuteOnUIThread(action)
|
||||
Dispatcher-->>MainWindow : Invoke UI update
|
||||
VM->>UIInvoker : Show dialog / message
|
||||
UIInvoker-->>MainWindow : Present UI element
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [App.axaml.cs](file://ClassicAssist.Avalonia/App.axaml.cs)
|
||||
- [Program.cs](file://ClassicAssist.Avalonia/Program.cs)
|
||||
- [MainWindow.axaml](file://ClassicAssist.Avalonia/Views/MainWindow.axaml)
|
||||
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
|
||||
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
|
||||
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
|
||||
|
||||
## Detailed Component Analysis
|
||||
|
||||
### BaseViewModel
|
||||
BaseViewModel centralizes MVVM essentials:
|
||||
- Property change notification: Derived classes raise notifications when properties change so bindings update automatically.
|
||||
- Command support: Common command infrastructure enables binding user actions to methods or ICommand implementations.
|
||||
- Thread safety helpers: Integration with dispatcher/invoker to ensure UI updates happen on the UI thread.
|
||||
|
||||
Best practices:
|
||||
- Always raise property change notifications after updating backing fields.
|
||||
- Use commands for all user interactions exposed to AXAML.
|
||||
- Avoid direct UI references; rely on dispatcher and UI invoker abstractions.
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class BaseViewModel {
|
||||
+RaisePropertyChanged(propertyName)
|
||||
+ExecuteCommand(command)
|
||||
+EnsureUiThread(action)
|
||||
}
|
||||
class MainWindowViewModel {
|
||||
+Properties...
|
||||
+Commands...
|
||||
+Initialize()
|
||||
}
|
||||
class DialogWindowViewModel {
|
||||
+Title
|
||||
+Message
|
||||
+OkCommand
|
||||
+CancelCommand
|
||||
}
|
||||
class GeneralControlViewModel {
|
||||
+State
|
||||
+RefreshCommand
|
||||
}
|
||||
MainWindowViewModel --|> BaseViewModel
|
||||
DialogWindowViewModel --|> BaseViewModel
|
||||
GeneralControlViewModel --|> BaseViewModel
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
|
||||
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
|
||||
- [DialogWindowViewModel.cs](file://ClassicAssist.Avalonia/ViewModels/DialogWindowViewModel.cs)
|
||||
- [GeneralControlViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/GeneralControlViewModel.cs)
|
||||
|
||||
**Section sources**
|
||||
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
|
||||
|
||||
### MainWindow and MainWindowViewModel
|
||||
The main window demonstrates typical MVVM usage:
|
||||
- AXAML defines controls and binds their properties and commands to MainWindowViewModel members.
|
||||
- Code-behind remains minimal, typically only wiring up initial DataContext if needed.
|
||||
- MainWindowViewModel exposes properties for UI state and commands for user actions, coordinating with models/managers.
|
||||
|
||||
Data binding flow:
|
||||
- User interaction triggers a command in MainWindowViewModel.
|
||||
- ViewModel updates properties and raises notifications.
|
||||
- AXAML bindings reflect changes automatically.
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant View as "MainWindow.axaml"
|
||||
participant VM as "MainWindowViewModel"
|
||||
participant Dispatcher as "AvaloniaDispatcher"
|
||||
View->>VM : Command invoked (e.g., "OpenSettings")
|
||||
VM->>VM : Perform action / update state
|
||||
VM->>Dispatcher : EnsureUiThread(updateUI)
|
||||
Dispatcher-->>View : Update bound properties
|
||||
View-->>User : Reflect new state
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [MainWindow.axaml](file://ClassicAssist.Avalonia/Views/MainWindow.axaml)
|
||||
- [MainWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/MainWindow.axaml.cs)
|
||||
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
|
||||
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
|
||||
|
||||
**Section sources**
|
||||
- [MainWindow.axaml](file://ClassicAssist.Avalonia/Views/MainWindow.axaml)
|
||||
- [MainWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/MainWindow.axaml.cs)
|
||||
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
|
||||
|
||||
### DialogWindow and DialogWindowViewModel
|
||||
Modal dialogs follow the same MVVM principles:
|
||||
- DialogWindow.axaml binds to DialogWindowViewModel properties (title, message) and commands (OK, Cancel).
|
||||
- DialogWindowViewModel encapsulates dialog-specific state and actions without referencing UI elements directly.
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start(["Show Dialog"]) --> Bind["Bind Title/Message/Commands"]
|
||||
Bind --> UserAction{"User clicks OK or Cancel?"}
|
||||
UserAction --> |OK| Confirm["Confirm action in ViewModel"]
|
||||
UserAction --> |Cancel| Close["Close dialog"]
|
||||
Confirm --> UpdateUI["Update UI via dispatcher"]
|
||||
UpdateUI --> End(["Dialog Closed"])
|
||||
Close --> End
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [DialogWindow.axaml](file://ClassicAssist.Avalonia/Views/DialogWindow.axaml)
|
||||
- [DialogWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/DialogWindow.axaml.cs)
|
||||
- [DialogWindowViewModel.cs](file://ClassicAssist.Avalonia/ViewModels/DialogWindowViewModel.cs)
|
||||
|
||||
**Section sources**
|
||||
- [DialogWindow.axaml](file://ClassicAssist.Avalonia/Views/DialogWindow.axaml)
|
||||
- [DialogWindow.axaml.cs](file://ClassicAssist.Avalonia/Views/DialogWindow.axaml.cs)
|
||||
- [DialogWindowViewModel.cs](file://ClassicAssist.Avalonia/ViewModels/DialogWindowViewModel.cs)
|
||||
|
||||
### GeneralControl and GeneralControlViewModel
|
||||
Reusable controls demonstrate encapsulation:
|
||||
- GeneralControl.axaml binds to GeneralControlViewModel properties and commands.
|
||||
- GeneralControlViewModel manages its own state and exposes a refresh command, keeping the control self-contained and testable.
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class GeneralControl {
|
||||
<<AXAML>>
|
||||
+Bindings to ViewModel
|
||||
}
|
||||
class GeneralControlViewModel {
|
||||
+State
|
||||
+RefreshCommand
|
||||
+Initialize()
|
||||
}
|
||||
GeneralControl --> GeneralControlViewModel : "DataContext"
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [GeneralControl.axaml](file://ClassicAssist.Avalonia/Views/GeneralControl.axaml)
|
||||
- [GeneralControl.axaml.cs](file://ClassicAssist.Avalonia/Views/GeneralControl.axaml.cs)
|
||||
- [GeneralControlViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/GeneralControlViewModel.cs)
|
||||
|
||||
**Section sources**
|
||||
- [GeneralControl.axaml](file://ClassicAssist.Avalonia/Views/GeneralControl.axaml)
|
||||
- [GeneralControl.axaml.cs](file://ClassicAssist.Avalonia/Views/GeneralControl.axaml.cs)
|
||||
- [GeneralControlViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/GeneralControlViewModel.cs)
|
||||
|
||||
### Dispatcher and UI Invoker Abstractions
|
||||
To keep ViewModels UI-framework agnostic:
|
||||
- IDispatcher and IUIInvoker define contracts for executing code on the UI thread and invoking UI operations.
|
||||
- AvaloniaDispatcher and AvaloniaUIInvoker provide concrete implementations for Avalonia.
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class IDispatcher {
|
||||
+ExecuteOnUIThread(action)
|
||||
}
|
||||
class IUIInvoker {
|
||||
+ShowDialog(dialogViewModel)
|
||||
+ShowMessage(message)
|
||||
}
|
||||
class AvaloniaDispatcher {
|
||||
+ExecuteOnUIThread(action)
|
||||
}
|
||||
class AvaloniaUIInvoker {
|
||||
+ShowDialog(dialogViewModel)
|
||||
+ShowMessage(message)
|
||||
}
|
||||
IDispatcher <|.. AvaloniaDispatcher
|
||||
IUIInvoker <|.. AvaloniaUIInvoker
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
|
||||
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
|
||||
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
|
||||
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
|
||||
|
||||
**Section sources**
|
||||
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
|
||||
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
|
||||
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
|
||||
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
|
||||
|
||||
## Dependency Analysis
|
||||
ViewModels depend on:
|
||||
- BaseViewModel for common functionality
|
||||
- Dispatcher and UI invoker abstractions for cross-thread UI updates
|
||||
- Models/managers for business logic (not shown here but present in Shared/Data)
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
VM_Main["MainWindowViewModel"] --> Base["BaseViewModel"]
|
||||
VM_Dialog["DialogWindowViewModel"] --> Base
|
||||
VM_General["GeneralControlViewModel"] --> Base
|
||||
Base --> Disp["IDispatcher"]
|
||||
Base --> Inv["IUIInvoker"]
|
||||
Disp --> DispImpl["AvaloniaDispatcher"]
|
||||
Inv --> InvImpl["AvaloniaUIInvoker"]
|
||||
```
|
||||
|
||||
**Diagram sources**
|
||||
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
|
||||
- [DialogWindowViewModel.cs](file://ClassicAssist.Avalonia/ViewModels/DialogWindowViewModel.cs)
|
||||
- [GeneralControlViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/GeneralControlViewModel.cs)
|
||||
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
|
||||
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
|
||||
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
|
||||
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
|
||||
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
|
||||
|
||||
**Section sources**
|
||||
- [MainWindowViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/MainWindowViewModel.cs)
|
||||
- [DialogWindowViewModel.cs](file://ClassicAssist.Avalonia/ViewModels/DialogWindowViewModel.cs)
|
||||
- [GeneralControlViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/GeneralControlViewModel.cs)
|
||||
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
|
||||
- [IDispatcher.cs](file://ClassicAssist.Shared/IDispatcher.cs)
|
||||
- [IUIInvoker.cs](file://ClassicAssist.Shared/IUIInvoker.cs)
|
||||
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
|
||||
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
|
||||
|
||||
## Performance Considerations
|
||||
- Minimize heavy work on the UI thread; offload to background tasks and marshal results back using the dispatcher.
|
||||
- Use efficient collections and avoid unnecessary property updates; batch updates where possible.
|
||||
- Keep AXAML bindings simple and avoid complex converters in hot paths.
|
||||
- Reuse ViewModels and controls when appropriate to reduce allocation overhead.
|
||||
|
||||
[No sources needed since this section provides general guidance]
|
||||
|
||||
## Troubleshooting Guide
|
||||
Common issues and resolutions:
|
||||
- UI not updating after property changes: Ensure property change notifications are raised correctly in BaseViewModel-derived classes.
|
||||
- Cross-thread exceptions: Always use the dispatcher to execute UI updates from background threads.
|
||||
- Commands not firing: Verify command bindings in AXAML and that commands are properly exposed and enabled.
|
||||
- Dialogs not showing: Use the UI invoker abstraction to present dialogs instead of direct UI calls.
|
||||
|
||||
**Section sources**
|
||||
- [BaseViewModel.cs](file://ClassicAssist.Shared/UI/ViewModels/BaseViewModel.cs)
|
||||
- [AvaloniaDispatcher.cs](file://ClassicAssist.Avalonia/AvaloniaDispatcher.cs)
|
||||
- [AvaloniaUIInvoker.cs](file://ClassicAssist.Avalonia/AvaloniaUIInvoker.cs)
|
||||
|
||||
## Conclusion
|
||||
ClassicAssist.Avalonia implements MVVM cleanly by separating Views (AXAML), ViewModels (C#), and Models (business logic). BaseViewModel standardizes property change notification and command support, while dispatcher and UI invoker abstractions ensure thread-safe UI updates. MainWindow, DialogWindow, and GeneralControl illustrate proper MVVM usage, enabling testable and maintainable presentation logic. Following these patterns helps keep the UI responsive and the codebase organized.
|
||||
|
||||
[No sources needed since this section summarizes without analyzing specific files]
|
||||
Reference in New Issue
Block a user