Files
2026-08-10 14:46:18 +02:00

336 lines
8.8 KiB
Markdown

# PropertyGrid Advanced Example - Technical Documentation
## Architecture Overview
The Advanced Example demonstrates a production-ready PropertyGrid implementation with enterprise-level features.
## Class Hierarchy
```
AdvancedConfiguration (INotifyPropertyChanged)
├── Server Configuration
│ ├── ServerName (string, validated)
│ ├── MaxConnections (int, range: 1-1000)
│ ├── ConnectionType (enum)
│ └── RequiresCertificate (computed, read-only)
├── Logging
│ ├── EnableLogging (bool)
│ ├── LogLevel (enum)
│ └── LogFilePath (string, advanced)
├── Network
│ ├── Timeout (TimeSpan)
│ └── NetworkSettings (nested object)
│ ├── Hostname (string, required)
│ ├── Port (int, range: 1-65535)
│ ├── UseProxy (bool)
│ └── ProxyAddress (string)
├── Database
│ └── DatabaseSettings (nested object)
│ ├── ConnectionString (string, required)
│ ├── Provider (enum)
│ ├── CommandTimeout (int)
│ ├── EnableRetry (bool)
│ └── MaxRetryCount (int, range: 1-10)
├── Security
│ ├── ApiKey (string, password)
│ └── AllowedIPs (List<string>)
├── Performance
│ ├── CompressionLevel (int, range: 0-9)
│ └── CacheSizeMB (int, range: 10-1024)
└── Metadata (all read-only)
├── CreatedDate (DateTime)
├── LastModified (DateTime)
└── ConfigurationId (Guid)
```
## Property Types Reference
### Basic Types
| Type | Example Property | Validation | Category |
|------|------------------|------------|----------|
| `string` | ServerName | Required, Length(3-50) | Server Configuration |
| `int` | MaxConnections | Range(1-1000) | Server Configuration |
| `bool` | EnableLogging | None | Logging |
| `decimal` | Price (QuickStart) | None | Financial |
### Advanced Types
| Type | Example Property | Notes | Category |
|------|------------------|-------|----------|
| `TimeSpan` | Timeout | Duration selection | Network |
| `DateTime` | CreatedDate | Date/time picker | Metadata |
| `Guid` | ConfigurationId | Unique identifier | Metadata |
| `List<string>` | AllowedIPs | Collection editing | Security |
### Enum Types
| Enum | Values | Description Support | Category |
|------|--------|---------------------|----------|
| ConnectionType | Http, Ssl, Tcp, Custom | ✅ | Server Configuration |
| LogLevel | Trace, Debug, Info, Warning, Error, Critical, None | ❌ | Logging |
| DatabaseProvider | SqlServer, PostgreSQL, MySQL, SQLite, Oracle | ✅ | Database |
### Nested Objects
| Object | Properties | Implements INPC | Category |
|--------|-----------|-----------------|----------|
| NetworkSettings | 4 properties | ✅ | Network |
| DatabaseSettings | 5 properties | ✅ | Database |
## Validation Rules
### String Validation
```csharp
[Required(ErrorMessage = "Server name is required")]
[StringLength(50, MinimumLength = 3,
ErrorMessage = "Server name must be between 3 and 50 characters")]
public string ServerName { get; set; }
```
### Numeric Range Validation
```csharp
[Range(1, 1000, ErrorMessage = "Max connections must be between 1 and 1000")]
public int MaxConnections { get; set; }
```
### Required Field Validation
```csharp
[Required]
public string Hostname { get; set; }
```
## Change Notification System
### Implementation Pattern
```csharp
private string _serverName = "Production-Server-01";
public string ServerName
{
get => _serverName;
set => SetProperty(ref _serverName, value);
}
protected bool SetProperty<T>(ref T field, T value,
[CallerMemberName] string? propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value))
return false;
field = value;
LastModified = DateTime.Now; // Auto-update metadata
OnPropertyChanged(propertyName);
return true;
}
```
### Cascading Updates
When `ConnectionType` changes, `RequiresCertificate` automatically updates:
```csharp
public ConnectionType ConnectionType
{
get => _connectionType;
set
{
if (SetProperty(ref _connectionType, value))
{
OnPropertyChanged(nameof(RequiresCertificate)); // Cascade
}
}
}
public bool RequiresCertificate => ConnectionType == ConnectionType.Ssl;
```
## Computed Properties
Computed properties derive their value from other properties:
```csharp
[Display(Name = "Requires Certificate", Order = 4)]
[Category("Server Configuration")]
[ReadOnly(true)]
public bool RequiresCertificate => ConnectionType == ConnectionType.Ssl;
```
**Benefits:**
- Always in sync with source properties
- No manual updates needed
- Marked as read-only
- Displayed in PropertyGrid but not editable
## Category Organization
Categories organize properties logically:
| Category | Purpose | Property Count |
|----------|---------|----------------|
| Server Configuration | Core server settings | 4 |
| Logging | Logging and diagnostics | 3 |
| Network | Network connectivity | 2 (+ nested) |
| Database | Database connection | 1 (nested) |
| Security | Authentication & access | 2 |
| Performance | Optimization settings | 2 |
| Metadata | System information | 3 |
## Property Ordering
Properties within categories are ordered using the `Order` attribute:
```csharp
[Display(Order = 1)] // First in category
[Display(Order = 2)] // Second in category
[Display(Order = 3)] // Third in category
```
## Special Attributes
### PasswordPropertyText
Hides sensitive information:
```csharp
[PasswordPropertyText(true)]
public string ApiKey { get; set; }
```
### EditorBrowsable
Groups advanced properties:
```csharp
[EditorBrowsable(EditorBrowsableState.Advanced)]
public string LogFilePath { get; set; }
```
### ReadOnly
Prevents property editing:
```csharp
[ReadOnly(true)]
public DateTime CreatedDate { get; set; }
```
## Data Binding in XAML
### Setting DataContext
```csharp
// In MainWindow.axaml.cs
public MainWindow()
{
InitializeComponent();
DataContext = new AdvancedConfiguration();
}
```
### PropertyGrid Binding
```xml
<Window x:DataType="models:AdvancedConfiguration">
<pg:PropertyGrid SelectedObject="{Binding}"
ShowCategories="True"
ShowDescriptions="True" />
</Window>
```
**Key Points:**
- `x:DataType` enables compiled bindings (.NET 10 requirement)
- `{Binding}` binds to the entire DataContext
- `ShowCategories` enables category grouping
- `ShowDescriptions` displays property descriptions
## Performance Considerations
### Efficient Change Notifications
```csharp
protected bool SetProperty<T>(ref T field, T value, ...)
{
// Early exit if value hasn't changed
if (EqualityComparer<T>.Default.Equals(field, value))
return false;
// Only notify if changed
field = value;
OnPropertyChanged(propertyName);
return true;
}
```
### Lazy Initialization
```csharp
private DatabaseSettings _databaseSettings = new(); // Initialized once
public DatabaseSettings DatabaseSettings => _databaseSettings;
```
## Testing Scenarios
### Validation Testing
1. Enter invalid server name (< 3 chars or > 50 chars)
2. Set MaxConnections outside range (< 1 or > 1000)
3. Leave required fields empty
### Change Notification Testing
1. Change ConnectionType to/from Ssl
2. Observe RequiresCertificate updates automatically
3. Note LastModified timestamp changes
### Nested Object Testing
1. Expand NetworkSettings
2. Modify nested properties
3. Verify changes propagate correctly
## Extension Points
### Adding New Properties
1. Add private backing field
2. Create public property with notifications
3. Add appropriate attributes
4. Assign to category
### Adding New Categories
Simply use a new category name:
```csharp
[Category("New Category Name")]
public string NewProperty { get; set; }
```
### Custom Validation
Implement `IDataErrorInfo` or `INotifyDataErrorInfo`:
```csharp
public class AdvancedConfiguration : INotifyPropertyChanged, IDataErrorInfo
{
public string Error => string.Empty;
public string this[string columnName]
{
get
{
// Return validation error for property
return string.Empty;
}
}
}
```
## Common Patterns
### ✅ DO
- Use INotifyPropertyChanged for all mutable properties
- Add descriptions to all properties
- Organize properties into logical categories
- Validate user input
- Use appropriate data types
- Mark computed properties as read-only
### ❌ DON'T
- Skip property change notifications
- Mix unrelated properties in same category
- Use generic category names like "Properties"
- Forget validation on user input
- Use string for structured data (use enums or objects)
- Make computed properties editable
## Summary
The Advanced Example demonstrates:
- ✅ 25+ properties across 7 categories
- ✅ 2 levels of nested objects
- ✅ Full INotifyPropertyChanged implementation
- ✅ Comprehensive validation
- ✅ Computed properties
- ✅ Multiple data types
- ✅ Production-ready code structure
This serves as a blueprint for real-world PropertyGrid implementations.