289 lines
7.7 KiB
C#
289 lines
7.7 KiB
C#
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;
|
|
}
|
|
}
|