Simple WPF: WPF自定義一個可以定義步長的SpinBox

mrchip發表於2024-07-09

最新內容優先釋出於個人部落格:小虎技術分享站,隨後逐步搬運到部落格園。

透過WPF的按鈕、文字輸入框實現了一個簡單的SpinBox數字輸入使用者元件並可以透過資料繫結數值和步長。本文中介紹了透過Xaml程式碼實現自定義元件的佈局,依賴屬性的定義和使用等知識點。

完整程式碼見Github

組合Xaml元件實現基本的元件功能

SpinBox由一個文字輸入框和兩個箭頭按鈕組成,我們在Xaml 程式碼中先把基本的佈局做好。其實可以發現自定義使用者控制元件佈局和普通的窗體佈局的Xaml程式碼差不多,只不過Xaml的根標籤從Window變成了UserControl

<UserControl x:Class="SpinBox.MySpinBox"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:SpinBox"
             mc:Ignorable="d" 
             d:DesignHeight="36" d:DesignWidth="92">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>

        <TextBox x:Name="txtBoxValue" Grid.Column="0"
                 TextAlignment="Center" VerticalContentAlignment="Center"/>
        <Grid Grid.Column="1">
            <Grid.RowDefinitions>
                <RowDefinition Height="5*"/>
                <RowDefinition Height="5*"/>
            </Grid.RowDefinitions>
            <Button Grid.Row="0" x:Name="btnPlus">&#x25B2;</Button>
            <Button Grid.Row="1" x:Name="btnMinor">&#x25BC;</Button>
        </Grid>
    </Grid>
</UserControl>

image

增加依賴屬性

因為我們是WPF中製作的使用者元件,因此希望輸入的數值、步長的配置等可以在Xaml中實現。因此我們需要給我們新建的使用者元件增加依賴屬性。這裡我們直接透過依賴屬性值變化的回撥函式來實現文字框資訊的更新。

    /// <summary>
    /// SpinBox.xaml 的互動邏輯
    /// </summary>
    [ContentProperty("Value")]
    public partial class MySpinBox : UserControl
    {

        /// <summary>
        /// DepedencyProperty for Step
        /// </summary>
        public static readonly DependencyProperty StepProperty
            = DependencyProperty.Register("Step", typeof(double),
                typeof(MySpinBox), new PropertyMetadata(1.0));

        /// <summary>
        /// DepedencyProperty for Value
        /// </summary>
        public static readonly DependencyProperty ValueProperty
            = DependencyProperty.Register("Value", typeof(double),
                typeof(MySpinBox), new FrameworkPropertyMetadata(0.0,
                     FrameworkPropertyMetadataOptions.BindsTwoWayByDefault
                    | FrameworkPropertyMetadataOptions.Journal
                    | FrameworkPropertyMetadataOptions.AffectsRender,
                    new PropertyChangedCallback(OnValueChanged))
                );


        public double Value
        {
            get => (double)GetValue(ValueProperty);
            set
            {
                if (Value != value)
                {
                    SetValue(ValueProperty, value);
                }
            }
        }

        public double Step
        {
            get => (double)GetValue(StepProperty);
            set
            {
                if (Step != value)
                {
                    SetValue(StepProperty, value);
                }
            }
        }

        private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var spinBox = d as MySpinBox;
            if (spinBox != null)
            {
                spinBox.txtBoxValue.Text = e.NewValue.ToString();
            }
        }
    }

接下來我們在MainWindow.xaml中增加剛剛編寫好的MySpinBox元件

<Window x:Class="SpinBox.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:SpinBox"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <local:MySpinBox MaxHeight="64" MaxWidth="128" Step="2" Value="5"/>
    </Grid>
</Window>

aIby9fvsAzbREuM8AxH16P-YfQPKyeZZWv7W_xdoOhY.png

增加事件處理

我們在自定義元件中增加按鈕元件的響應

<Button Grid.Row="0" x:Name="btnPlus" Click="btnPlus_Click">&#x25B2;</Button>
<Button Grid.Row="1" x:Name="btnMinor" Click="btnMinor_Click">&#x25BC;</Button>

在C#程式碼中增加對應的響應邏輯就能實現完整的效果

private void btnPlus_Click(object sender, RoutedEventArgs e)
{
    Value += Step;
}

private void btnMinor_Click(object sender, RoutedEventArgs e)
{
    Value -= Step;
}

最後需要說明下的是按鈕的Unicode值得十六進位制表示分別是0x25B20x25BCXaml本質是一種XML文字,因此在其中表示Unicode要使用XML對應的語法格式。

最終效果

0mXuWATdDulTh9cq3puJypQD824gtsmMleGRQOb-_Co.gif

相關文章