368 lines
7.0 KiB
Markdown
368 lines
7.0 KiB
Markdown
# 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<T>(ref T field, T value,
|
|
[CallerMemberName] string? propertyName = null)
|
|
{
|
|
if (EqualityComparer<T>.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<T>` - 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
|
|
<Window xmlns:pg="using:Avalonia.PropertyGrid.Controls"
|
|
xmlns:models="using:YourNamespace.Models"
|
|
x:DataType="models:YourModel">
|
|
|
|
<pg:PropertyGrid SelectedObject="{Binding}"
|
|
ShowCategories="True"
|
|
ShowDescriptions="True" />
|
|
</Window>
|
|
```
|
|
|
|
### 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!
|