# PropertyGrid Quick Reference Guide ## Essential Attributes ### Display Attribute Controls property appearance in PropertyGrid: ```csharp [Display( Name = "Display Name", // Shown in UI Description = "Property help", // Tooltip/description Order = 1 // Sort order in category )] public string MyProperty { get; set; } ``` ### Category Attribute Groups related properties: ```csharp [Category("Server Settings")] public string ServerName { get; set; } ``` ### ReadOnly Attribute Makes property non-editable: ```csharp [ReadOnly(true)] public string ComputedValue { get; set; } ``` ## Validation Attributes ### Required ```csharp [Required(ErrorMessage = "This field is required")] public string ServerName { get; set; } ``` ### Range ```csharp [Range(1, 100, ErrorMessage = "Value must be between 1 and 100")] public int Connections { get; set; } ``` ### StringLength ```csharp [StringLength(50, MinimumLength = 3, ErrorMessage = "Length must be between 3 and 50")] public string Name { get; set; } ``` ### RegularExpression ```csharp [RegularExpression(@"^\d{3}-\d{2}-\d{4}$", ErrorMessage = "Invalid format")] public string SSN { get; set; } ``` ## Special Attributes ### PasswordPropertyText Hides text input: ```csharp [PasswordPropertyText(true)] public string Password { get; set; } ``` ### EditorBrowsable Controls visibility of advanced properties: ```csharp [EditorBrowsable(EditorBrowsableState.Advanced)] public string AdvancedSetting { get; set; } ``` ## INotifyPropertyChanged Pattern ### Basic Implementation ```csharp public class MyModel : INotifyPropertyChanged { private string _name = string.Empty; public string Name { get => _name; set { if (_name != value) { _name = value; OnPropertyChanged(); } } } public event PropertyChangedEventHandler? PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string? name = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); } } ``` ### Helper Method Pattern ```csharp protected bool SetProperty(ref T field, T value, [CallerMemberName] string? propertyName = null) { if (EqualityComparer.Default.Equals(field, value)) return false; field = value; OnPropertyChanged(propertyName); return true; } // Usage public string Name { get => _name; set => SetProperty(ref _name, value); } ``` ## Supported Property Types ### Basic Types - `string` - Text input - `int`, `long`, `short` - Numeric input - `double`, `float`, `decimal` - Decimal input - `bool` - Checkbox - `DateTime` - Date/time picker - `TimeSpan` - Duration input - `Guid` - GUID input - `Uri` - URL input ### Complex Types - `enum` - Dropdown list - Nested objects - Expandable group - `List` - Collection editor (if supported) ### Nullable Types All value types can be nullable: ```csharp public int? OptionalNumber { get; set; } public DateTime? OptionalDate { get; set; } ``` ## Enum with Descriptions ```csharp public enum Status { [Description("Not yet started")] NotStarted, [Description("Currently in progress")] InProgress, [Description("Successfully completed")] Completed, [Description("Failed with errors")] Failed } ``` ## Nested Objects ```csharp public class Configuration { [Display(Name = "Database Settings")] [Category("Database")] public DatabaseSettings Database { get; set; } = new(); } public class DatabaseSettings { [Display(Name = "Server")] public string Server { get; set; } = "localhost"; [Display(Name = "Port")] [Range(1, 65535)] public int Port { get; set; } = 5432; } ``` ## XAML Setup ### Basic PropertyGrid ```xml ``` ### Code-Behind ```csharp public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); DataContext = new YourModel(); } } ``` ## Computed Properties Properties that derive from other properties: ```csharp private bool _isEnabled; public bool IsEnabled { get => _isEnabled; set { if (SetProperty(ref _isEnabled, value)) { OnPropertyChanged(nameof(StatusText)); } } } [ReadOnly(true)] public string StatusText => IsEnabled ? "Enabled" : "Disabled"; ``` ## Common Patterns ### Server Configuration ```csharp [Display(Name = "Server Address", Order = 1)] [Category("Connection")] [Required] public string ServerAddress { get; set; } = "localhost"; [Display(Name = "Port", Order = 2)] [Category("Connection")] [Range(1, 65535)] public int Port { get; set; } = 8080; [Display(Name = "Use SSL", Order = 3)] [Category("Security")] public bool UseSsl { get; set; } = true; ``` ### Credentials ```csharp [Display(Name = "Username")] [Category("Authentication")] [Required] public string Username { get; set; } = string.Empty; [Display(Name = "Password")] [Category("Authentication")] [PasswordPropertyText(true)] public string Password { get; set; } = string.Empty; ``` ### File Paths ```csharp [Display(Name = "Log Directory")] [Category("Logging")] [EditorBrowsable(EditorBrowsableState.Advanced)] public string LogDirectory { get; set; } = @"C:\Logs\"; ``` ## Tips & Tricks ### 1. Property Order Gaps Use gaps (10, 20, 30) for easy insertion: ```csharp [Display(Order = 10)] // Easy to insert Order = 15 later [Display(Order = 20)] [Display(Order = 30)] ``` ### 2. Category Naming Use clear, hierarchical names: - ✅ "Server Configuration" - ✅ "Database / Connection" - ❌ "Misc" - ❌ "Settings" ### 3. Meaningful Descriptions ```csharp // ❌ Bad [Display(Description = "The timeout")] // ✅ Good [Display(Description = "Connection timeout in seconds (1-300)")] ``` ### 4. Validation Messages ```csharp // ❌ Generic [Required(ErrorMessage = "Required")] // ✅ Specific [Required(ErrorMessage = "Server name is required for connection")] ``` ### 5. Default Values Always provide sensible defaults: ```csharp public int MaxConnections { get; set; } = 100; // ✅ Good default public int Timeout { get; set; } = 30; // ✅ Reasonable public string Server { get; set; } = string.Empty; // ✅ Safe default ``` ## Debugging ### Check Binding Add this to see binding errors: ```csharp .LogToTrace(areas: new[] { LogArea.Binding, LogArea.Property }) ``` ### Verify DataContext ```csharp public MainWindow() { InitializeComponent(); var model = new MyModel(); DataContext = model; // Verify System.Diagnostics.Debug.WriteLine($"DataContext: {DataContext?.GetType().Name}"); } ``` ## Performance ### Lazy Loading ```csharp private DatabaseSettings? _database; public DatabaseSettings Database => _database ??= new DatabaseSettings(); ``` ### Efficient Notifications ```csharp // Only notify if value actually changed if (_field == value) return; ``` ## See Also - [QuickStartExample](../QuickStartExample/) - Basic usage - [AdvancedExample](../AdvancedExample/) - Complex scenarios - [Technical Documentation](./TECHNICAL.md) - Deep dive --- **Need help?** Check the examples or review the PropertyGrid source code!