initial commit

This commit is contained in:
Matthias Heil
2026-08-10 14:46:18 +02:00
commit c946aa63e6
69 changed files with 8865 additions and 0 deletions
@@ -0,0 +1,288 @@
using System;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.PropertyGrid.Models;
namespace Avalonia.PropertyGrid.Editors;
/// <summary>
/// Base class for property editors
/// </summary>
public abstract class PropertyEditor : ContentControl
{
/// <summary>
/// Defines the PropertyItem property.
/// </summary>
public static readonly StyledProperty<PropertyItem?> PropertyItemProperty =
AvaloniaProperty.Register<PropertyEditor, PropertyItem?>(nameof(PropertyItem));
/// <summary>
/// Gets or sets the property item being edited.
/// </summary>
public PropertyItem? PropertyItem
{
get => GetValue(PropertyItemProperty);
set => SetValue(PropertyItemProperty, value);
}
/// <summary>
/// Called when the PropertyItem changes.
/// </summary>
protected virtual void OnPropertyItemChanged(PropertyItem? oldValue, PropertyItem? newValue)
{
if (oldValue != null)
{
UnbindFromProperty(oldValue);
}
if (newValue != null)
{
BindToProperty(newValue);
}
}
/// <summary>
/// Binds the editor to the property item.
/// </summary>
protected abstract void BindToProperty(PropertyItem item);
/// <summary>
/// Unbinds the editor from the property item.
/// </summary>
protected abstract void UnbindFromProperty(PropertyItem item);
}
/// <summary>
/// Editor for string properties
/// </summary>
public class StringEditor : PropertyEditor
{
private TextBox? _textBox;
/// <inheritdoc/>
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
_textBox = new TextBox();
Content = _textBox;
}
/// <inheritdoc/>
protected override void BindToProperty(PropertyItem item)
{
if (_textBox != null)
{
_textBox.Bind(TextBox.TextProperty,
new Avalonia.Data.Binding(nameof(PropertyItem.Value))
{
Source = item,
Mode = Avalonia.Data.BindingMode.TwoWay
});
_textBox.IsReadOnly = item.IsReadOnly;
}
}
/// <inheritdoc/>
protected override void UnbindFromProperty(PropertyItem item)
{
_textBox?.ClearValue(TextBox.TextProperty);
}
}
/// <summary>
/// Editor for numeric properties
/// </summary>
public class NumericEditor : PropertyEditor
{
private NumericUpDown? _numericUpDown;
/// <inheritdoc/>
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
_numericUpDown = new NumericUpDown
{
Increment = 1,
FormatString = "0.##"
};
Content = _numericUpDown;
}
/// <inheritdoc/>
protected override void BindToProperty(PropertyItem item)
{
if (_numericUpDown != null)
{
_numericUpDown.Bind(NumericUpDown.ValueProperty,
new Avalonia.Data.Binding(nameof(PropertyItem.Value))
{
Source = item,
Mode = Avalonia.Data.BindingMode.TwoWay
});
_numericUpDown.IsReadOnly = item.IsReadOnly;
// Adjust increment based on type
if (item.PropertyType == typeof(int) || item.PropertyType == typeof(long))
{
_numericUpDown.Increment = 1;
_numericUpDown.FormatString = "0";
}
else if (item.PropertyType == typeof(double) || item.PropertyType == typeof(float))
{
_numericUpDown.Increment = 0.1m;
_numericUpDown.FormatString = "0.00";
}
}
}
/// <inheritdoc/>
protected override void UnbindFromProperty(PropertyItem item)
{
_numericUpDown?.ClearValue(NumericUpDown.ValueProperty);
}
}
/// <summary>
/// Editor for boolean properties
/// </summary>
public class BooleanEditor : PropertyEditor
{
private CheckBox? _checkBox;
/// <inheritdoc/>
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
_checkBox = new CheckBox
{
HorizontalAlignment = Layout.HorizontalAlignment.Left
};
Content = _checkBox;
}
/// <inheritdoc/>
protected override void BindToProperty(PropertyItem item)
{
if (_checkBox != null)
{
_checkBox.Bind(CheckBox.IsCheckedProperty,
new Avalonia.Data.Binding(nameof(PropertyItem.Value))
{
Source = item,
Mode = Avalonia.Data.BindingMode.TwoWay
});
_checkBox.IsEnabled = !item.IsReadOnly;
}
}
/// <inheritdoc/>
protected override void UnbindFromProperty(PropertyItem item)
{
_checkBox?.ClearValue(CheckBox.IsCheckedProperty);
}
}
/// <summary>
/// Editor for enum properties
/// </summary>
public class EnumEditor : PropertyEditor
{
private ComboBox? _comboBox;
/// <inheritdoc/>
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
_comboBox = new ComboBox();
Content = _comboBox;
}
/// <inheritdoc/>
protected override void BindToProperty(PropertyItem item)
{
if (_comboBox != null && item.PropertyType.IsEnum)
{
_comboBox.ItemsSource = Enum.GetValues(item.PropertyType);
_comboBox.Bind(ComboBox.SelectedItemProperty,
new Avalonia.Data.Binding(nameof(PropertyItem.Value))
{
Source = item,
Mode = Avalonia.Data.BindingMode.TwoWay
});
_comboBox.IsEnabled = !item.IsReadOnly;
}
}
/// <inheritdoc/>
protected override void UnbindFromProperty(PropertyItem item)
{
_comboBox?.ClearValue(ComboBox.SelectedItemProperty);
}
}
/// <summary>
/// Editor for DateTime properties
/// </summary>
public class DateTimeEditor : PropertyEditor
{
private DatePicker? _datePicker;
/// <inheritdoc/>
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
_datePicker = new DatePicker();
Content = _datePicker;
}
/// <inheritdoc/>
protected override void BindToProperty(PropertyItem item)
{
if (_datePicker != null)
{
_datePicker.Bind(DatePicker.SelectedDateProperty,
new Avalonia.Data.Binding(nameof(PropertyItem.Value))
{
Source = item,
Mode = Avalonia.Data.BindingMode.TwoWay,
Converter = new DateTimeToDateTimeOffsetConverter()
});
_datePicker.IsEnabled = !item.IsReadOnly;
}
}
/// <inheritdoc/>
protected override void UnbindFromProperty(PropertyItem item)
{
_datePicker?.ClearValue(DatePicker.SelectedDateProperty);
}
}
/// <summary>
/// Converter for DateTime to DateTimeOffset
/// </summary>
internal class DateTimeToDateTimeOffsetConverter : Avalonia.Data.Converters.IValueConverter
{
public object? Convert(object? value, Type targetType, object? parameter, System.Globalization.CultureInfo culture)
{
if (value is DateTime dt)
{
return new DateTimeOffset(dt);
}
return null;
}
public object? ConvertBack(object? value, Type targetType, object? parameter, System.Globalization.CultureInfo culture)
{
if (value is DateTimeOffset dto)
{
return dto.DateTime;
}
return null;
}
}