336 lines
8.8 KiB
Markdown
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.
|