You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Avalonia如何创建带确认取消功能的自定义Popup选择器

Avalonia 简易自定义弹出选择器实现方案

核心实现思路

参考原生DatePicker的Popup弹出交互逻辑,在Popup容器内同时嵌套选择内容区和底部操作按钮,用临时变量存储弹出时的当前选中值,用户点击确认则将新选择同步到控件公开属性,点击取消则回滚选择并关闭弹出层。

具体实现步骤

1. 自定义控件XAML样式定义

先创建自定义选择器的默认模板,核心包含触发弹出的显示区域、Popup弹出容器两部分:

<Style Selector="local:CustomSelector">
  <Setter Property="Template">
    <ControlTemplate>
      <Grid>
        <!-- 触发弹出的输入显示按钮 -->
        <Button x:Name="PART_ShowPopupButton"
                Content="{TemplateBinding SelectedValue, FallbackValue='请选择'}"
                HorizontalAlignment="Stretch"/>
        <!-- 弹出层容器 -->
        <Popup x:Name="PART_Popup"
               Placement="Bottom"
               PlacementTarget="{Binding #PART_ShowPopupButton}"
               IsLightDismissEnabled="False">
          <Border Background="White"
                  BorderBrush="Gray"
                  BorderThickness="1"
                  MinWidth="200">
            <StackPanel>
              <!-- 选择内容区域,可根据业务替换为列表、日期选择等任意组件 -->
              <ListBox x:Name="PART_SelectorList"
                       Items="{TemplateBinding SelectItems}"
                       Margin="8"
                       MaxHeight="200"/>
              <!-- 底部操作按钮区 -->
              <DockPanel Margin="4" HorizontalAlignment="Right">
                <Button x:Name="PART_CancelButton" Content="取消" Margin="4 0"/>
                <Button x:Name="PART_OkButton" Content="确认" Margin="4 0"/>
              </DockPanel>
            </StackPanel>
          </Border>
        </Popup>
      </Grid>
    </ControlTemplate>
  </Setter>
</Style>

2. 控件后台逻辑实现

创建CustomSelector.cs类,继承TemplatedControl,实现依赖属性和交互逻辑:

using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using System.Collections;

public class CustomSelector : TemplatedControl
{
    // 可选列表依赖属性
    public static readonly StyledProperty<IEnumerable> SelectItemsProperty =
        AvaloniaProperty.Register<CustomSelector, IEnumerable>(nameof(SelectItems));
    
    // 选中值依赖属性
    public static readonly StyledProperty<object> SelectedValueProperty =
        AvaloniaProperty.Register<CustomSelector, object>(nameof(SelectedValue));

    private object _tempSelectedValue;
    private Popup _popup;
    private Button _showPopupBtn;
    private Button _okBtn;
    private Button _cancelBtn;
    private ListBox _selectorList;

    public IEnumerable SelectItems
    {
        get => GetValue(SelectItemsProperty);
        set => SetValue(SelectItemsProperty, value);
    }

    public object SelectedValue
    {
        get => GetValue(SelectedValueProperty);
        set => SetValue(SelectedValueProperty, value);
    }

    protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
    {
        base.OnApplyTemplate(e);
        
        // 获取模板内控件引用
        _popup = e.NameScope.Find<Popup>("PART_Popup");
        _showPopupBtn = e.NameScope.Find<Button>("PART_ShowPopupButton");
        _okBtn = e.NameScope.Find<Button>("PART_OkButton");
        _cancelBtn = e.NameScope.Find<Button>("PART_CancelButton");
        _selectorList = e.NameScope.Find<ListBox>("PART_SelectorList");

        // 绑定交互事件
        if (_showPopupBtn != null)
            _showPopupBtn.Click += (s, e) => ShowPopup();
        
        if (_okBtn != null)
            _okBtn.Click += (s, e) => ConfirmSelection();
        
        if (_cancelBtn != null)
            _cancelBtn.Click += (s, e) => CancelSelection();
    }

    private void ShowPopup()
    {
        // 弹出前备份当前选中值
        _tempSelectedValue = SelectedValue;
        if (_selectorList != null)
            _selectorList.SelectedItem = SelectedValue;
        _popup.IsOpen = true;
    }

    private void ConfirmSelection()
    {
        // 确认选择同步到公开属性
        SelectedValue = _selectorList?.SelectedItem ?? _tempSelectedValue;
        _popup.IsOpen = false;
    }

    private void CancelSelection()
    {
        // 取消选择回滚状态
        _selectorList.SelectedItem = _tempSelectedValue;
        _popup.IsOpen = false;
    }
}

3. 控件使用示例

在页面中直接引用自定义控件即可:

<Window xmlns:local="clr-namespace:替换为你自己的命名空间">
  <StackPanel Margin="16">
    <local:CustomSelector Width="200"
                          SelectItems="{Binding 你的选项列表}"
                          SelectedValue="{Binding 你的绑定选中值}"/>
  </StackPanel>
</Window>

可选优化点

  • 可将Popup的IsLightDismissEnabled属性设为True,实现点击空白处自动关闭,可自行定义空白处关闭时触发确认还是取消逻辑
  • 选择内容区可根据需求替换为任意自定义组件,比如颜色选择器、多级联动选择等
  • 可添加SelectionChanged路由事件,满足选中值变更时的额外业务逻辑需求

内容的提问来源于stack exchange,提问作者Fatih

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 07:24:01