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

8.8 KiB

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

[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

[Range(1, 1000, ErrorMessage = "Max connections must be between 1 and 1000")]
public int MaxConnections { get; set; }

Required Field Validation

[Required]
public string Hostname { get; set; }

Change Notification System

Implementation Pattern

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:

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:

[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:

[Display(Order = 1)]  // First in category
[Display(Order = 2)]  // Second in category
[Display(Order = 3)]  // Third in category

Special Attributes

PasswordPropertyText

Hides sensitive information:

[PasswordPropertyText(true)]
public string ApiKey { get; set; }

EditorBrowsable

Groups advanced properties:

[EditorBrowsable(EditorBrowsableState.Advanced)]
public string LogFilePath { get; set; }

ReadOnly

Prevents property editing:

[ReadOnly(true)]
public DateTime CreatedDate { get; set; }

Data Binding in XAML

Setting DataContext

// In MainWindow.axaml.cs
public MainWindow()
{
	InitializeComponent();
	DataContext = new AdvancedConfiguration();
}

PropertyGrid Binding

<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

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

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:

[Category("New Category Name")]
public string NewProperty { get; set; }

Custom Validation

Implement IDataErrorInfo or INotifyDataErrorInfo:

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.