创建自定义滑块

Creating a Custom Slider

我创建了一个自定义滑块,但是更改滑块的值时没有触发 ValueChanged 事件,任何人都可以指出原因。

using Mobile.Resources;
using System;
using System.Windows.Input;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace Mobile.Controls
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class SliderControl : Grid
    {
        #region Bindable Property

        public event EventHandler<TextChangedEventArgs> SliderValueChanged;
        public event EventHandler<ValueChangedEventArgs> ValueChanged;

        public static readonly BindableProperty MinimumValueProperty =
            BindableProperty.Create("MinimumValue", typeof(double), typeof(SliderControl), defaultValue: 0.00);

        public static readonly BindableProperty MiddleValueProperty =
            BindableProperty.Create("MiddleValue", typeof(double), typeof(SliderControl), defaultValue: 50.00);

        public static readonly BindableProperty MaximumValueProperty =
            BindableProperty.Create("MaximumValue", typeof(double), typeof(SliderControl), defaultValue: 100.00);

        public static readonly BindableProperty SliderValueProperty =
            BindableProperty.Create(nameof(SliderValue), typeof(double), typeof(SliderControl), defaultValue: 0.00);

        public static readonly BindableProperty ValidationExceedMessageProperty =
            BindableProperty.Create("ValidationExceedMessage", typeof(string), typeof(SliderControl), defaultValue: "Limits exceeded");

        public static readonly BindableProperty IsValidationExceedProperty =
            BindableProperty.Create("IsValidationExceed", typeof(bool), typeof(SliderControl), defaultValue: false);

        #endregion

        #region Properties

        public double MinimumValue
        {
            get { return (double)GetValue(MinimumValueProperty); }
            set { SetValue(MinimumValueProperty, value); }
        }

        public double MiddleValue
        {
            get { return (double)GetValue(MiddleValueProperty); }
            set { SetValue(MiddleValueProperty, value); }
        }

        public double MaximumValue
        {
            get { return (double)GetValue(MaximumValueProperty); }
            set { SetValue(MaximumValueProperty, value); }
        }

        public double SliderValue
        {
            set => SetValue(SliderValueProperty, value);
            get => (double)GetValue(SliderValueProperty);
        }

        public bool IsValidationExceed
        {
            get { return (bool)GetValue(IsValidationExceedProperty); }
            set { SetValue(IsValidationExceedProperty, value); }
        }

        public string ValidationExceedMessage
        {
            get { return (string)GetValue(ValidationExceedMessageProperty); }
            set { SetValue(ValidationExceedMessageProperty, value); }
        }

        #endregion

        #region Constructor

        public SliderControl()
        {
            InitializeComponent();
        }

        #endregion

        #region Method

    private void Entry_TextChanged(object sender, TextChangedEventArgs e)
    {
        if (!string.IsNullOrEmpty(e.NewTextValue))
        {
            try
            {
                int.Parse(e.NewTextValue);
                this.SliderValue = double.Parse(e.NewTextValue);
            }
            catch (Exception)
            {
                this.SliderValue = 0;
            }
        }
        else
        {
            this.SliderValue = 0;
        }

        ValidateNumericValue();
        SliderValueChanged?.Invoke(sender, e);
    }

    private void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
    {
        SliderValue = args.NewValue;

        ValidateNumericValue();
        ValueChanged?.Invoke(sender, args);
    }

这是 SliderControl.cs 的 XAML.cs,我也错过了如果我更改滑块值,它应该反映在 Entry 组件中的事件。

<?xml version="1.0" encoding="UTF-8" ?>
<Grid
    x:Class="Mobile.Controls.SliderControl"
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:common="clr-namespace:Mobile.Common"
    xmlns:control="clr-namespace:Mobile.Controls"
    x:Name="component"
    RowDefinitions="Auto,Auto"
    VerticalOptions="Center">

<Grid RowDefinitions="Auto, *">
    <StackLayout Orientation="Horizontal">
        <Slider Maximum="{x:Binding MaximumValue, Source={x:Reference component}}"
                Minimum="0"
                WidthRequest="300"
                VerticalOptions="FillAndExpand"
                Value="{x:Binding SliderValue, Source={x:Reference component}}"
                ValueChanged="OnSliderValueChanged"/>
        <Entry x:Name="SliderText"
               Placeholder="0"
               WidthRequest="50"
               VerticalOptions="CenterAndExpand"
               TextChanged="Entry_TextChanged"/>
    </StackLayout>
    <StackLayout Orientation="Horizontal" Grid.Row="1">
        <Label Text="0"
               HorizontalOptions="Start"
               MinimumWidthRequest="100"/>
        <Label Text="{x:Binding MiddleValue, Source={x:Reference component}}"
               HorizontalOptions="Center"
               Margin="120,0,0,0"
               MinimumWidthRequest="100"/>
        <Label Text="{x:Binding MaximumValue, Source={x:Reference component}}"
               HorizontalOptions="End"
               Margin="120,0,0,0"
               MinimumWidthRequest="100"/>
    </StackLayout>
</Grid>

这是一个用于创建动态滑块控件的新实例。

private void GenerateSliderContent(SQViewModel question)
{
    if (question.Entity.QuestionAnswer != null)
    {
        var slider = new SliderControl();

        var maxValue = question.Entity.MaxPrice ?? 100;
        var minValue = question.Entity.MinPrice ?? 0;

        slider.MaximumValue = Math.Max(minValue, maxValue);
        slider.MinimumValue = Math.Min(minValue, maxValue);
        slider.MiddleValue = slider.MaximumValue / 2;
        slider.WidthRequest = 100;
        slider.IsEnabled = !this.IsReadOnly;

        slider.SliderValue = question.Answer == null ? 0 : question.Answer.Entity.ValueNumeric.Value;

        slider.ValueChanged += (sender, e) => Slider_ValueChanged(question, e.NewValue);

        this.Children.Add(slider);
    }
}

private void Slider_ValueChanged(SQViewModel question, double value)
{
    if (question.Answer != null)
    {
        question.Answer.Entity.ValueNumeric = value;
    }
    else
    {
        SAnswer answer = new SAnswer
        {
            SurveyId = Guid.NewGuid(),
            AccountId = AccountId,
            STId = question.Entity.STId,
            STQAnswerId = Guid.NewGuid(),
            STQId = question.Entity.Id,
            ValueNumeric = value,
        };

        question.Answer = new SAnswerViewModel(answer);
    }
}

您可以轻松自定义颜色、缩略图和轨道颜色。基本定制可以通过两种方式完成:

  • 来自属性检查器
  • 在 viewDidLoad() 中以编程方式

这是link

您可以参考下面的代码。

  1. 在您的 SliderControl Xaml 中添加 ValueChanged:

    <Slider Maximum="100"
                 Minimum="0"
                 WidthRequest="300"
                 VerticalOptions="FillAndExpand"                    
                 ValueChanged="Slider_ValueChanged"
                 Value="{x:Binding SliderValue, Source={x:Reference component}}"/>
    
  2. 在后面的SliderControl代码中注册事件:

     public event EventHandler<ValueChangedEventArgs> ValueChanged;
     private void Slider_ValueChanged(object sender, ValueChangedEventArgs e)
     {
         ValueChanged?.Invoke(this, e);
     }
    
  3. 用法:我在 Xaml 中提供了有关如何执行此操作的简单代码,您也可以在 C# 代码中执行此操作。

    <local:SliderControl ValueChanged="SliderControl_ValueChanged"></local:SliderControl>