本意是想在Avalonia中实现一个类似按钮组的单选控件,同时又想展示所有的选项。
最后决定采用附加属性的方式实现,让ItemsControl具备UniformGrid的能力
最终效果如图
ItemsControlAttached代码如下
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
using Avalonia.Interactivity;
namespace Infrastructure.Avalonia.Attachment;
public class ItemsControlAttached : AvaloniaObject
{
static ItemsControlAttached()
{
UseGridProperty.Changed.AddClassHandler<Interactive>(HandleUseGridChanged);
}
private static void HandleUseGridChanged(Interactive arg1, AvaloniaPropertyChangedEventArgs arg2)
{
if (arg1 is ItemsControl ic && arg2.NewValue is bool useGrid && useGrid)
{
var uniformGrid = new UniformGrid();
// 直接设置属性
uniformGrid.Rows = GetRows(ic);
uniformGrid.Columns = GetColumns(ic);
// 添加事件处理器以在属性更改时更新 UniformGrid
ic.GetObservable(RowsProperty).Subscribe(rows => uniformGrid.Rows = rows);
ic.GetObservable(ColumnsProperty).Subscribe(columns => uniformGrid.Columns = columns);
// 设置 ItemsPanel
ic.ItemsPanel = new FuncTemplate<Panel>(() => uniformGrid);
}
}
public static readonly AttachedProperty<int> RowsProperty =
AvaloniaProperty.RegisterAttached<ListBox, int>(
"Rows", typeof(ItemsControlAttached));
public static readonly AttachedProperty<int> ColumnsProperty =
AvaloniaProperty.RegisterAttached<ListBox, int>(
"Columns", typeof(ItemsControlAttached));
public static readonly AttachedProperty<bool> UseGridProperty =
AvaloniaProperty.RegisterAttached<ListBox, bool>(
"UseGrid", typeof(ItemsControlAttached));
public static int GetRows(AvaloniaObject element) => element.GetValue(RowsProperty);
public static void SetRows(AvaloniaObject element, int value) => element.SetValue(RowsProperty, value);
public static int GetColumns(AvaloniaObject element) => element.GetValue(ColumnsProperty);
public static void SetColumns(AvaloniaObject element, int value) => element.SetValue(ColumnsProperty, value);
public static bool GetUseGrid(AvaloniaObject element) => element.GetValue(UseGridProperty);
public static void SetUseGrid(AvaloniaObject element, bool value) => element.SetValue(UseGridProperty, value);
}
使用代码如下
<TabItem Header="GridListBox">
<UniformGrid Columns="2">
<UniformGrid.Styles>
<Style Selector="ListBox">
<Setter Property="BorderBrush" Value="Orange"></Setter>
<Setter Property="BorderThickness" Value="1"></Setter>
<Setter Property="ItemTemplate" >
<Setter.Value>
<DataTemplate>
<Button Content="{Binding}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"></Button>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</UniformGrid.Styles>
<ListBox ItemsSource="{Binding GridListBoxSource}"></ListBox>
<ListBox ItemsSource="{Binding GridListBoxSource}" attachment:ItemsControlAttached.UseGrid="True" attachment:ItemsControlAttached.Rows="2"></ListBox>
</UniformGrid>
</TabItem>