用户雾里看花 发表于 2024-7-9 14:24:20

Simple WPF: WPF自定义一个可以定义步长的SpinBox

最新内容优先发布于个人博客:小虎技术分享站,随后逐步搬运到博客园。
通过WPF的按钮、文本输入框实现了一个简单的SpinBox数字输入用户组件并可以通过数据绑定数值和步长。本文中介绍了通过Xaml代码实现自定义组件的布局,依赖属性的定义和使用等知识点。
完整代码见Github
组合Xaml组件实现基本的组件功能

SpinBox由一个文本输入框和两个箭头按钮组成,我们在Xaml 代码中先把基本的布局做好。其实可以发现自定义用户控件布局和普通的窗体布局的Xaml代码差不多,只不过Xaml的根标签从Window变成了UserControl 。
<UserControl x:
             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"
<Window x:
      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> TextAlignment="Center" VerticalContentAlignment="Center"/>
      <Grid Grid.Column="1">
            <Grid.RowDefinitions>
<Window x:
      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><RowDefinition Height="5*"/>
<Window x:
      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><RowDefinition Height="5*"/>
            </Grid.RowDefinitions>
            <Button Grid.Row="0" x:Name="btnPlus">▲</Button>
            <Button Grid.Row="1" x:Name="btnMinor">▼</Button>
      </Grid>
    </Grid>
</UserControl>
增加依赖属性

因为我们是WPF中制作的用户组件,因此希望输入的数值、步长的配置等可以在Xaml中实现。因此我们需要给我们新建的用户组件增加依赖属性。这里我们直接通过依赖属性值变化的回调函数来实现文本框信息的更新。
    /// <summary>
    /// SpinBox.xaml 的交互逻辑
    /// </summary>
   
    public partial class MySpinBox : UserControl
    {

      /// <summary>
      /// DepedencyProperty for Step
      /// </summary>
      public static readonly DependencyProperty StepProperty
            = DependencyProperty.Register("Step", typeof(double),
<Window x:
      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>typeof(MySpinBox), new PropertyMetadata(1.0));

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


      public double Value
      {
            get => (double)GetValue(ValueProperty);
            set
            {
<Window x:
      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>if (Value != value)
<Window x:
      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>{
<Window x:
      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>    SetValue(ValueProperty, value);
<Window x:
      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>}
            }
      }

      public double Step
      {
            get => (double)GetValue(StepProperty);
            set
            {
<Window x:
      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>if (Step != value)
<Window x:
      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>{
<Window x:
      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>    SetValue(StepProperty, value);
<Window x:
      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>}
            }
      }

      private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
      {
            var spinBox = d as MySpinBox;
            if (spinBox != null)
            {
<Window x:
      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>spinBox.txtBoxValue.Text = e.NewValue.ToString();
            }
      }
    }接下来我们在MainWindow.xaml中增加刚刚编写好的MySpinBox组件
<Window x:
      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>
增加事件处理

我们在自定义组件中增加按钮组件的响应
<Button Grid.Row="0" x:Name="btnPlus" Click="btnPlus_Click">▲</Button>
<Button Grid.Row="1" x:Name="btnMinor" Click="btnMinor_Click">▼</Button>在C#代码中增加对应的响应逻辑就能实现完整的效果
private void btnPlus_Click(object sender, RoutedEventArgs e)
{
    Value += Step;
}

private void btnMinor_Click(object sender, RoutedEventArgs e)
{
    Value -= Step;
}最后需要说明下的是按钮的Unicode值得十六进制表示分别是0x25B2 和0x25BC 。Xaml本质是一种XML文本,因此在其中表示Unicode要使用XML对应的语法格式。
最终效果



来源:https://www.cnblogs.com/mrchip/p/18290697
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: Simple WPF: WPF自定义一个可以定义步长的SpinBox