initial commit
This commit is contained in:
@@ -0,0 +1,367 @@
|
||||
# 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!
|
||||
Reference in New Issue
Block a user