feat: add more properties.
This commit is contained in:
@@ -1,59 +1,65 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Metadata;
|
||||
using Avalonia.Layout;
|
||||
using Ursa.Common;
|
||||
|
||||
namespace Ursa.Controls;
|
||||
|
||||
[PseudoClasses(PC_FixedWidth)]
|
||||
public class Form: ItemsControl
|
||||
{
|
||||
#region Attached Properties
|
||||
|
||||
public static readonly AttachedProperty<object?> LabelProperty =
|
||||
AvaloniaProperty.RegisterAttached<Form, Control, object?>("Label");
|
||||
public static void SetLabel(Control obj, object? value) => obj.SetValue(LabelProperty, value);
|
||||
public static object? GetLabel(Control obj) => obj.GetValue(LabelProperty);
|
||||
public const string PC_FixedWidth = ":fixed-width";
|
||||
|
||||
public static readonly StyledProperty<GridLength> LabelWidthProperty = AvaloniaProperty.Register<Form, GridLength>(
|
||||
nameof(LabelWidth));
|
||||
|
||||
public static readonly AttachedProperty<bool> IsRequiredProperty =
|
||||
AvaloniaProperty.RegisterAttached<Form, Control, bool>("IsRequired");
|
||||
public static void SetIsRequired(Control obj, bool value) => obj.SetValue(IsRequiredProperty, value);
|
||||
public static bool GetIsRequired(Control obj) => obj.GetValue(IsRequiredProperty);
|
||||
|
||||
public static readonly AttachedProperty<GridLength> LabelWidthProperty =
|
||||
AvaloniaProperty.RegisterAttached<Form, Control, GridLength>("LabelWidth");
|
||||
|
||||
public static void SetLabelWidth(Control obj, GridLength value) => obj.SetValue(LabelWidthProperty, value);
|
||||
public static GridLength GetLabelWidth(Control obj) => obj.GetValue(LabelWidthProperty);
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Behavior:
|
||||
/// <para>Fixed Width: all labels are with fixed length. </para>
|
||||
/// <para>Star: all labels are aligned by max length. </para>
|
||||
/// <para>Auto: labels are not aligned. </para>
|
||||
/// </summary>
|
||||
public GridLength LabelWidth
|
||||
{
|
||||
get => GetValue(LabelWidthProperty);
|
||||
set => SetValue(LabelWidthProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<Position> LabelPositionProperty = AvaloniaProperty.Register<Form, Position>(
|
||||
nameof(LabelPosition));
|
||||
/// <summary>
|
||||
/// Only Left and Top work.
|
||||
/// </summary>
|
||||
nameof(LabelPosition), defaultValue: Position.Top);
|
||||
|
||||
public Position LabelPosition
|
||||
{
|
||||
get => GetValue(LabelPositionProperty);
|
||||
set => SetValue(LabelPositionProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<Position> LabelAlignmentProperty = AvaloniaProperty.Register<Form, Position>(
|
||||
nameof(LabelAlignment));
|
||||
/// <summary>
|
||||
/// Only Left and Right work.
|
||||
/// </summary>
|
||||
public Position LabelAlignment
|
||||
public static readonly StyledProperty<HorizontalAlignment> LabelAlignmentProperty = AvaloniaProperty.Register<Form, HorizontalAlignment>(
|
||||
nameof(LabelAlignment), defaultValue: HorizontalAlignment.Left);
|
||||
|
||||
public HorizontalAlignment LabelAlignment
|
||||
{
|
||||
get => GetValue(LabelAlignmentProperty);
|
||||
set => SetValue(LabelAlignmentProperty, value);
|
||||
}
|
||||
|
||||
static Form()
|
||||
{
|
||||
LabelWidthProperty.Changed.AddClassHandler<Form, GridLength>((x, args) => x.LabelWidthChanged(args));
|
||||
}
|
||||
|
||||
private void LabelWidthChanged(AvaloniaPropertyChangedEventArgs<GridLength> args)
|
||||
{
|
||||
var newValue = args.NewValue.Value;
|
||||
bool isFixed = newValue.IsStar || newValue.IsAbsolute;
|
||||
PseudoClasses.Set(PC_FixedWidth, isFixed);
|
||||
}
|
||||
|
||||
protected override bool NeedsContainerOverride(object? item, int index, out object? recycleKey)
|
||||
{
|
||||
recycleKey = null;
|
||||
return item is FormItem or FormGroup;
|
||||
return item is not FormItem && item is not FormGroup;
|
||||
}
|
||||
|
||||
protected override Control CreateContainerForItemOverride(object? item, int index, object? recycleKey)
|
||||
@@ -62,27 +68,8 @@ public class Form: ItemsControl
|
||||
return new FormItem()
|
||||
{
|
||||
Content = control,
|
||||
[!LabelProperty] = control.GetObservable(Form.LabelProperty).ToBinding(),
|
||||
[!IsRequiredProperty] = control.GetObservable(Form.IsRequiredProperty).ToBinding(),
|
||||
[!FormItem.LabelProperty] = control[!FormItem.LabelProperty],
|
||||
[!FormItem.IsRequiredProperty] = control[!FormItem.IsRequiredProperty],
|
||||
};
|
||||
}
|
||||
|
||||
protected override void PrepareContainerForItemOverride(Control container, object? item, int index)
|
||||
{
|
||||
base.PrepareContainerForItemOverride(container, item, index);
|
||||
if (container is FormGroup group)
|
||||
{
|
||||
if (!group.IsSet(FormGroup.LabelWidthProperty))
|
||||
{
|
||||
group[!LabelWidthProperty] = this.GetObservable(LabelWidthProperty).ToBinding();
|
||||
}
|
||||
}
|
||||
else if (container is FormItem formItem)
|
||||
{
|
||||
if(!formItem.IsSet(FormItem.LabelWidthProperty))
|
||||
{
|
||||
formItem[!LabelWidthProperty] = this.GetObservable(LabelWidthProperty).ToBinding();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,13 +6,6 @@ namespace Ursa.Controls;
|
||||
|
||||
public class FormGroup: HeaderedItemsControl
|
||||
{
|
||||
public static readonly StyledProperty<GridLength> LabelWidthProperty = Form.LabelWidthProperty.AddOwner<FormGroup>();
|
||||
|
||||
public GridLength LabelWidth
|
||||
{
|
||||
get => GetValue(LabelWidthProperty);
|
||||
set => SetValue(LabelWidthProperty, value);
|
||||
}
|
||||
protected override bool NeedsContainerOverride(object? item, int index, out object? recycleKey)
|
||||
{
|
||||
recycleKey = null;
|
||||
@@ -25,17 +18,9 @@ public class FormGroup: HeaderedItemsControl
|
||||
return new FormItem
|
||||
{
|
||||
Content = control,
|
||||
[!FormItem.LabelProperty] = control.GetObservable(Form.LabelProperty).ToBinding(),
|
||||
[!FormItem.IsRequiredProperty] = control.GetObservable(Form.IsRequiredProperty).ToBinding(),
|
||||
[!FormItem.LabelProperty] = control[!FormItem.LabelProperty],
|
||||
[!FormItem.IsRequiredProperty] = control[!FormItem.IsRequiredProperty],
|
||||
};
|
||||
}
|
||||
|
||||
protected override void PrepareContainerForItemOverride(Control container, object? item, int index)
|
||||
{
|
||||
base.PrepareContainerForItemOverride(container, item, index);
|
||||
if (container is FormItem formItem)
|
||||
{
|
||||
formItem.LabelWidth = LabelWidth;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,46 +1,93 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Metadata;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Reactive;
|
||||
using Avalonia.VisualTree;
|
||||
using Irihi.Avalonia.Shared.Helpers;
|
||||
using Ursa.Common;
|
||||
|
||||
namespace Ursa.Controls;
|
||||
|
||||
[PseudoClasses(PC_Horizontal, PC_NoLabel)]
|
||||
public class FormItem: ContentControl
|
||||
{
|
||||
public static readonly StyledProperty<object?> LabelProperty = AvaloniaProperty.Register<FormItem, object?>(
|
||||
nameof(Label));
|
||||
public const string PC_Horizontal = ":horizontal";
|
||||
public const string PC_NoLabel = ":no-label";
|
||||
|
||||
#region Attached Properties
|
||||
public static readonly AttachedProperty<object?> LabelProperty =
|
||||
AvaloniaProperty.RegisterAttached<FormItem, Control, object?>("Label");
|
||||
public static void SetLabel(Control obj, object? value) => obj.SetValue(LabelProperty, value);
|
||||
public static object? GetLabel(Control obj) => obj.GetValue(LabelProperty);
|
||||
|
||||
|
||||
public object? Label
|
||||
{
|
||||
get => GetValue(LabelProperty);
|
||||
set => SetValue(LabelProperty, value);
|
||||
}
|
||||
public static readonly AttachedProperty<bool> IsRequiredProperty =
|
||||
AvaloniaProperty.RegisterAttached<FormItem, Control, bool>("IsRequired");
|
||||
public static void SetIsRequired(Control obj, bool value) => obj.SetValue(IsRequiredProperty, value);
|
||||
public static bool GetIsRequired(Control obj) => obj.GetValue(IsRequiredProperty);
|
||||
|
||||
public static readonly StyledProperty<bool> IsRequiredProperty = AvaloniaProperty.Register<FormItem, bool>(
|
||||
nameof(IsRequired));
|
||||
public static readonly AttachedProperty<bool> NoLabelProperty =
|
||||
AvaloniaProperty.RegisterAttached<FormItem, Control, bool>("NoLabel");
|
||||
|
||||
public bool IsRequired
|
||||
{
|
||||
get => GetValue(IsRequiredProperty);
|
||||
set => SetValue(IsRequiredProperty, value);
|
||||
}
|
||||
public static void SetNoLabel(Control obj, bool value) => obj.SetValue(NoLabelProperty, value);
|
||||
public static bool GetNoLabel(Control obj) => obj.GetValue(NoLabelProperty);
|
||||
#endregion
|
||||
|
||||
private List<IDisposable> _formSubscriptions = new List<IDisposable>();
|
||||
|
||||
public static readonly StyledProperty<GridLength> LabelWidthProperty = AvaloniaProperty.Register<FormItem, GridLength>(
|
||||
public static readonly StyledProperty<double> LabelWidthProperty = AvaloniaProperty.Register<FormItem, double>(
|
||||
nameof(LabelWidth));
|
||||
|
||||
public GridLength LabelWidth
|
||||
public double LabelWidth
|
||||
{
|
||||
get => GetValue(LabelWidthProperty);
|
||||
set => SetValue(LabelWidthProperty, value);
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<HorizontalAlignment> LabelAlignmentProperty = AvaloniaProperty.Register<FormItem, HorizontalAlignment>(
|
||||
nameof(LabelAlignment));
|
||||
|
||||
public HorizontalAlignment LabelAlignment
|
||||
{
|
||||
get => GetValue(LabelAlignmentProperty);
|
||||
set => SetValue(LabelAlignmentProperty, value);
|
||||
}
|
||||
|
||||
static FormItem()
|
||||
{
|
||||
LabelWidthProperty.Changed.AddClassHandler<FormItem, GridLength>((x, args) => x.LabelWidthChanged(args));
|
||||
PropertyToPseudoClassMixin.Attach<FormItem>(NoLabelProperty, PC_NoLabel);
|
||||
}
|
||||
|
||||
private void LabelWidthChanged(AvaloniaPropertyChangedEventArgs<GridLength> args)
|
||||
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
|
||||
{
|
||||
GridLength? length = args.GetNewValue<GridLength>();
|
||||
|
||||
base.OnAttachedToVisualTree(e);
|
||||
var form = this.GetVisualAncestors().OfType<Form>().FirstOrDefault();
|
||||
if (form is not null)
|
||||
{
|
||||
_formSubscriptions.Clear();
|
||||
var labelSubscription = form
|
||||
.GetObservable(Form.LabelWidthProperty)
|
||||
.Subscribe(new AnonymousObserver<GridLength>(length => { LabelWidth = length.IsAbsolute ? length.Value : double.NaN; }));
|
||||
var positionSubscription = form
|
||||
.GetObservable(Form.LabelPositionProperty)
|
||||
.Subscribe(new AnonymousObserver<Position>(position => { PseudoClasses.Set(PC_Horizontal, position == Position.Left);}));
|
||||
var alignmentSubscription = form
|
||||
.GetObservable(Form.LabelAlignmentProperty)
|
||||
.Subscribe(new AnonymousObserver<HorizontalAlignment>(alignment => { LabelAlignment = alignment; }));
|
||||
_formSubscriptions.Add(labelSubscription);
|
||||
_formSubscriptions.Add(positionSubscription);
|
||||
_formSubscriptions.Add(alignmentSubscription);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
|
||||
{
|
||||
base.OnDetachedFromVisualTree(e);
|
||||
foreach (var subscription in _formSubscriptions)
|
||||
{
|
||||
subscription.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace Ursa.Controls;
|
||||
|
||||
public class FormPanel
|
||||
{
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user