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

如何在Avalonia(C#)中创建双Thumb滑块组件

Avalonia原生的Slider组件只支持单Thumb,要实现双Thumb滑块,有两种常用方案:

方案1:使用社区现成的RangeSlider组件

直接用NuGet包Avalonia.RangeSlider,这是社区维护的专门支持双Thumb的滑块组件:

  1. 安装NuGet包:Install-Package Avalonia.RangeSlider
  2. 在XAML中引用命名空间,然后使用控件:
xmlns:controls="clr-namespace:Avalonia.Controls;assembly=Avalonia.RangeSlider"

<controls:RangeSlider Grid.Column="1" 
                      HorizontalAlignment="Right" 
                      VerticalAlignment="Center" 
                      Margin="0,0,65,0" 
                      Height="35" 
                      Width="150"
                      Minimum="0" 
                      Maximum="100"
                      LowerValue="20" 
                      UpperValue="80"/>

通过绑定LowerValue和UpperValue就能获取两个Thumb对应的范围值,控件自带拖动、值限制等逻辑,上手很快。

方案2:自定义双Thumb滑块控件

如果不想依赖第三方包,可以自己实现一个自定义控件,步骤如下:

1. 创建自定义控件类

using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Media;

public class DoubleThumbSlider : Control
{
    public static readonly StyledProperty<double> MinimumProperty =
        AvaloniaProperty.Register<DoubleThumbSlider, double>(nameof(Minimum), 0.0);

    public static readonly StyledProperty<double> MaximumProperty =
        AvaloniaProperty.Register<DoubleThumbSlider, double>(nameof(Maximum), 100.0);

    public static readonly StyledProperty<double> LowerValueProperty =
        AvaloniaProperty.Register<DoubleThumbSlider, double>(nameof(LowerValue), 20.0);

    public static readonly StyledProperty<double> UpperValueProperty =
        AvaloniaProperty.Register<DoubleThumbSlider, double>(nameof(UpperValue), 80.0);

    public double Minimum
    {
        get => GetValue(MinimumProperty);
        set => SetValue(MinimumProperty, value);
    }

    public double Maximum
    {
        get => GetValue(MaximumProperty);
        set => SetValue(MaximumProperty, value);
    }

    public double LowerValue
    {
        get => GetValue(LowerValueProperty);
        set => SetValue(LowerValueProperty, Math.Clamp(value, Minimum, UpperValue));
    }

    public double UpperValue
    {
        get => GetValue(UpperValueProperty);
        set => SetValue(UpperValueProperty, Math.Clamp(value, LowerValue, Maximum));
    }

    private Thumb _lowerThumb;
    private Thumb _upperThumb;
    private Rectangle _track;
    private Rectangle _rangeFill;

    protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
    {
        base.OnApplyTemplate(e);

        _lowerThumb = e.NameScope.Find<Thumb>("LowerThumb");
        _upperThumb = e.NameScope.Find<Thumb>("UpperThumb");
        _track = e.NameScope.Find<Rectangle>("Track");
        _rangeFill = e.NameScope.Find<Rectangle>("RangeFill");

        _lowerThumb.DragDelta += LowerThumb_DragDelta;
        _upperThumb.DragDelta += UpperThumb_DragDelta;
        UpdateVisuals();
    }

    private void LowerThumb_DragDelta(object sender, VectorEventArgs e)
    {
        var newLowerValue = LowerValue + (e.Vector.X / _track.Bounds.Width) * (Maximum - Minimum);
        LowerValue = Math.Clamp(newLowerValue, Minimum, UpperValue);
        UpdateVisuals();
    }

    private void UpperThumb_DragDelta(object sender, VectorEventArgs e)
    {
        var newUpperValue = UpperValue + (e.Vector.X / _track.Bounds.Width) * (Maximum - Minimum);
        UpperValue = Math.Clamp(newUpperValue, LowerValue, Maximum);
        UpdateVisuals();
    }

    private void UpdateVisuals()
    {
        if (_track == null || _rangeFill == null) return;

        var trackWidth = _track.Bounds.Width;
        var rangeLength = Maximum - Minimum;
        var lowerPosition = ((LowerValue - Minimum) / rangeLength) * trackWidth;
        var upperPosition = ((UpperValue - Minimum) / rangeLength) * trackWidth;

        _rangeFill.Width = upperPosition - lowerPosition;
        _rangeFill.Margin = new Thickness(lowerPosition, 0, 0, 0);
    }

    protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
    {
        base.OnPropertyChanged(change);
        if (change.Property == LowerValueProperty || change.Property == UpperValueProperty ||
            change.Property == MinimumProperty || change.Property == MaximumProperty)
        {
            UpdateVisuals();
        }
    }
}

2. 定义控件模板

在App.xaml或者页面的资源字典中添加控件样式模板:

<Style TargetType="local:DoubleThumbSlider">
    <Setter Property="Template">
        <ControlTemplate>
            <Grid Height="{TemplateBinding Height}" Width="{TemplateBinding Width}">
                <Rectangle x:Name="Track" 
                           Height="4" 
                           VerticalAlignment="Center" 
                           Fill="#E0E0E0" 
                           CornerRadius="2"/>
                <Rectangle x:Name="RangeFill" 
                           Height="4" 
                           VerticalAlignment="Center" 
                           Fill="#2196F3" 
                           CornerRadius="2"/>
                <Thumb x:Name="LowerThumb" 
                       Width="16" 
                       Height="16" 
                       Background="White" 
                       BorderBrush="#2196F3" 
                       BorderThickness="2" 
                       CornerRadius="8"
                       Margin="-8,0,0,0">
                    <Thumb.Styles>
                        <Style TargetType="Thumb">
                            <Setter Property="Template">
                                <ControlTemplate>
                                    <Ellipse Fill="{TemplateBinding Background}" 
                                             Stroke="{TemplateBinding BorderBrush}" 
                                             StrokeThickness="{TemplateBinding BorderThickness}"/>
                                </ControlTemplate>
                            </Setter>
                        </Style>
                    </Thumb.Styles>
                </Thumb>
                <Thumb x:Name="UpperThumb" 
                       Width="16" 
                       Height="16" 
                       Background="White" 
                       BorderBrush="#2196F3" 
                       BorderThickness="2" 
                       CornerRadius="8"
                       Margin="-8,0,0,0">
                    <Thumb.Styles>
                        <Style TargetType="Thumb">
                            <Setter Property="Template">
                                <ControlTemplate>
                                    <Ellipse Fill="{TemplateBinding Background}" 
                                             Stroke="{TemplateBinding BorderBrush}" 
                                             StrokeThickness="{TemplateBinding BorderThickness}"/>
                                </ControlTemplate>
                            </Setter>
                        </Style>
                    </Thumb.Styles>
                </Thumb>
            </Grid>
        </ControlTemplate>
    </Setter>
</Style>

3. 使用自定义控件

在XAML页面中引用命名空间并使用:

xmlns:local="clr-namespace:你的项目命名空间"

<local:DoubleThumbSlider Grid.Column="1" 
                         HorizontalAlignment="Right" 
                         VerticalAlignment="Center" 
                         Margin="0,0,65,0" 
                         Height="35" 
                         Width="150"
                         Minimum="0" 
                         Maximum="100"
                         LowerValue="20" 
                         UpperValue="80"/>

这个自定义控件实现了基础的双Thumb拖动逻辑,还可以根据需求修改样式(比如颜色、Thumb形状)或者添加更多功能(如点击轨道跳转)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 15:20:22