forked from amkovkov/GranuSightSoftware2
feat: SectionPanel ChildrenSource and ChildrenTemplate
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Specialized;
|
||||
|
||||
using Avalonia;
|
||||
using Avalonia.Animation;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Templates;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Styling;
|
||||
@@ -64,6 +68,18 @@ public class SectionPanel : Panel
|
||||
get => GetValue(CanScrollBackwardProperty);
|
||||
set => SetValue(CanScrollBackwardProperty, value);
|
||||
}
|
||||
public static readonly StyledProperty<IEnumerable?> ChildrenSourceProperty = AvaloniaProperty.Register<SectionPanel, IEnumerable?>(nameof(ChildrenSource), null, defaultBindingMode: Avalonia.Data.BindingMode.OneWay);
|
||||
public IEnumerable? ChildrenSource
|
||||
{
|
||||
get => GetValue(ChildrenSourceProperty);
|
||||
set => SetValue(ChildrenSourceProperty, value);
|
||||
}
|
||||
public static readonly StyledProperty<IDataTemplate?> ChildrenTemplateProperty = AvaloniaProperty.Register<ItemsControl, IDataTemplate?>(nameof(ChildrenTemplate), null);
|
||||
public IDataTemplate? ChildrenTemplate
|
||||
{
|
||||
get => GetValue(ChildrenTemplateProperty);
|
||||
set => SetValue(ChildrenTemplateProperty, value);
|
||||
}
|
||||
|
||||
private readonly Dictionary<Control, int> _childIndeces = new Dictionary<Control, int>();
|
||||
private bool _initialized = false;
|
||||
@@ -78,13 +94,153 @@ public class SectionPanel : Panel
|
||||
CanScrollBackward = Cyclic || CurrentIndex != 0;
|
||||
panel.InvalidateArrange();
|
||||
});
|
||||
ChildrenSourceProperty.Changed.AddClassHandler<SectionPanel>((panel, ea) =>
|
||||
{
|
||||
if (panel != this)
|
||||
return;
|
||||
(ea.OldValue as INotifyCollectionChanged)?.CollectionChanged -= panel.OnChildrenSourceCollectionChanged;
|
||||
(ea.NewValue as INotifyCollectionChanged)?.CollectionChanged += panel.OnChildrenSourceCollectionChanged;
|
||||
panel.Children.Clear();
|
||||
if (ea.NewValue is IEnumerable enumerable)
|
||||
{
|
||||
IEnumerable<Control> controls;
|
||||
if (ChildrenTemplate is null)
|
||||
controls = enumerable.OfType<Control>();
|
||||
else
|
||||
controls = enumerable.Cast<object?>()
|
||||
.Where(ChildrenTemplate.Match)
|
||||
.Select(i =>
|
||||
{
|
||||
var control = ChildrenTemplate.Build(i);
|
||||
control?.DataContext = i;
|
||||
return control;
|
||||
})
|
||||
.OfType<Control>();
|
||||
|
||||
foreach (var control in controls)
|
||||
panel.Children.Add(control);
|
||||
}
|
||||
panel.InvalidateArrange();
|
||||
});
|
||||
Children.CollectionChanged += (_, ea) =>
|
||||
{
|
||||
CanScrollForward = Cyclic || CurrentIndex != Children.Count() - 1;
|
||||
CanScrollBackward = Cyclic || CurrentIndex != 0;
|
||||
CanScrollForward = (Cyclic && Children.Count() > 1) || CurrentIndex != Children.Count() - 1;
|
||||
CanScrollBackward = (Cyclic && Children.Count() > 1) || CurrentIndex != 0;
|
||||
};
|
||||
}
|
||||
|
||||
protected void OnChildrenSourceCollectionChanged(object? sender, NotifyCollectionChangedEventArgs ea)
|
||||
{
|
||||
switch (ea.Action)
|
||||
{
|
||||
case NotifyCollectionChangedAction.Add:
|
||||
{
|
||||
if (ea.NewItems is null)
|
||||
return;
|
||||
|
||||
var index = ea.NewStartingIndex >= 0
|
||||
? ea.NewStartingIndex
|
||||
: Children.Count;
|
||||
|
||||
IEnumerable<Control> controls;
|
||||
if (ChildrenTemplate is null)
|
||||
controls = ea.NewItems.OfType<Control>();
|
||||
else
|
||||
controls = ea.NewItems.Cast<object?>()
|
||||
.Where(ChildrenTemplate.Match)
|
||||
.Select(i =>
|
||||
{
|
||||
var control = ChildrenTemplate.Build(i);
|
||||
control?.DataContext = i;
|
||||
return control;
|
||||
})
|
||||
.OfType<Control>();
|
||||
|
||||
foreach (Control control in controls)
|
||||
Children.Insert(index++, control);
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case NotifyCollectionChangedAction.Remove:
|
||||
{
|
||||
if (ea.OldItems is null)
|
||||
return;
|
||||
|
||||
foreach (Control control in ea.OldItems)
|
||||
Children.Remove(control);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case NotifyCollectionChangedAction.Replace:
|
||||
{
|
||||
if (ea.OldItems is not null)
|
||||
foreach (Control control in ea.OldItems)
|
||||
Children.Remove(control);
|
||||
|
||||
if (ea.NewItems is not null)
|
||||
{
|
||||
var index = ea.NewStartingIndex >= 0 ?
|
||||
ea.NewStartingIndex :
|
||||
Children.Count;
|
||||
|
||||
foreach (Control control in ea.NewItems)
|
||||
Children.Insert(index++, control);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case NotifyCollectionChangedAction.Move:
|
||||
{
|
||||
if (ea.OldItems is not IEnumerable<Control> oldControls || oldControls.Count() == 0)
|
||||
return;
|
||||
|
||||
var control = oldControls.First();
|
||||
|
||||
if (ea.OldStartingIndex >= 0)
|
||||
Children.RemoveAt(ea.OldStartingIndex);
|
||||
|
||||
if (ea.NewStartingIndex >= 0)
|
||||
Children.Insert(ea.NewStartingIndex, control);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case NotifyCollectionChangedAction.Reset:
|
||||
{
|
||||
Children.Clear();
|
||||
|
||||
if (ChildrenSource is null)
|
||||
break;
|
||||
|
||||
IEnumerable<Control> controls;
|
||||
if (ChildrenTemplate is null)
|
||||
controls = ChildrenSource.OfType<Control>();
|
||||
else
|
||||
controls = ChildrenSource.Cast<object?>()
|
||||
.Where(ChildrenTemplate.Match)
|
||||
.Select(i =>
|
||||
{
|
||||
var control = ChildrenTemplate.Build(i);
|
||||
control?.DataContext = i;
|
||||
return control;
|
||||
})
|
||||
.OfType<Control>();
|
||||
|
||||
foreach (var control in controls)
|
||||
Children.Add(control);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
InvalidateMeasure();
|
||||
InvalidateArrange();
|
||||
}
|
||||
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
foreach (var child in Children)
|
||||
|
||||
Reference in New Issue
Block a user