zoukankan      html  css  js  c++  java
  • WPF自定义控件之双滑块Slider

      今天写搜索界面,有许多值范围搜索的项,先是做了两个Textbox加两个Slider来实现选择起始->结束值的范围,后来发现这样用户操作性太不好,前台代码又很臃肿,干脆想办法写了个自定义的控件。首先来看下最终效果吧:

       


      具体的交互基本就是左边框是起始值,右边框是终止值,它们数据的是和两个滑块绑定的,会互相更新。左边的滑块是不能拖到右边滑块之外的,同理右边也不能到左边,如果输入的值超出(小于)上限值(下限),则会把值取为上限值(下限)。

      我的思路就是定义两个Slider,然后拼起来,哈哈!好吧,来看前台代码:

     1 <UserControl x:Class="FS.PresentationManagement.Controls.SilderArrange"
     2              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     3              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     4              Name="UC_Arrange" Loaded="UC_Arrange_Loaded">
     5     <StackPanel Orientation="Horizontal" Height="{Binding ElementName=UC_Arrange,Path=SilderHeight}" >
     6         <TextBox Text="{Binding ElementName=SL_Bat1,Path=Value}" KeyUp="TextBox_KeyUp1" Width="35" Margin="0,3" BorderBrush="CornflowerBlue" />
     7         <Canvas Width="{Binding ElementName=UC_Arrange,Path=SilderWidth}" Margin="0,0,5,0">
     8             <Slider Name="SL_Bat1"
     9                 Value="{Binding ElementName=UC_Arrange,Path=StartValue}"
    10                 Minimum="{Binding ElementName=UC_Arrange,Path=Minimum}"
    11                 Maximum="{Binding ElementName=UC_Arrange,Path=Maximum}"
    12                 SelectionStart="{Binding ElementName=UC_Arrange,Path=StartValue}"
    13                 SelectionEnd="{Binding ElementName=UC_Arrange,Path=EndValue}"
    14                 Width="{Binding ElementName=UC_Arrange,Path=SilderWidth}"
    15                 TickFrequency="{Binding ElementName=UC_Arrange,Path=SliderTickFrequency}"
    16                 FocusVisualStyle="{x:Null}"
    17                 CacheMode="BitmapCache"
    18                 IsSelectionRangeEnabled="True"
    19                 TickPlacement="BottomRight"
    20                 IsSnapToTickEnabled="True"
    21                 VerticalAlignment="Center"
    22                 Margin="2"
    23                 ValueChanged="SL_Bat1_ValueChanged">
    24                 <Slider.Clip>
    25                     <RectangleGeometry Rect="{Binding ElementName=UC_Arrange,Path=StartRect}" />
    26                 </Slider.Clip>
    27             </Slider>
    28             <Slider Name="SL_Bat2" 
    29                 Value="{Binding ElementName=UC_Arrange,Path=EndValue}" 
    30                 Minimum="{Binding ElementName=UC_Arrange,Path=Minimum}" 
    31                 Maximum="{Binding ElementName=UC_Arrange,Path=Maximum}" 
    32                 SelectionStart="{Binding ElementName=UC_Arrange,Path=StartValue}" 
    33                 SelectionEnd="{Binding ElementName=UC_Arrange,Path=EndValue}" 
    34                 Width="{Binding ElementName=UC_Arrange,Path=SilderWidth}"
    35                 TickFrequency="{Binding ElementName=UC_Arrange,Path=SliderTickFrequency}"
    36                 FocusVisualStyle="{x:Null}"
    37                 CacheMode="BitmapCache"
    38                 IsSelectionRangeEnabled="True"                
    39                 TickPlacement="BottomRight"
    40                 IsSnapToTickEnabled="True"
    41                 VerticalAlignment="Center"
    42                 Margin="2"
    43                 ValueChanged="SL_Bat2_ValueChanged">
    44                 <Slider.Clip>
    45                     <RectangleGeometry Rect="{Binding ElementName=UC_Arrange,Path=EndRect}" />
    46                 </Slider.Clip>                
    47             </Slider>
    48         </Canvas>
    49         <TextBox Text="{Binding ElementName=SL_Bat2,Path=Value}" KeyUp="TextBox_KeyUp2" Width="35" Margin="0,3" BorderBrush="CornflowerBlue"/>        
    50     </StackPanel>
    51 </UserControl>

      没错,我这里用的是Canvas,让两个Slider重叠,然后通过Clip剪裁,然后各个控件的值基本都是绑定到了后台的依赖属性,剪裁的矩形范围也不例外,后台会根据滑块的位置实时更新前台界面,让它们看起来很“和谐”。考虑到剪裁可能产生的效率问题,我把两个Slider的CacheMode都设置成了“BitmapCache”,也就是说会用GPU来计算界面元素。FocusVisualStyle="{x:Null}"这个设置则是让XP的机器显示Slider的时候不会出现很丑的虚线框。
      至于其它设置,都是常规的设置了,这些绑定到后台的除了剪裁的依赖属性设置的是private外,其它都是public,也就是说,使用的时候可以自己再给这些属性赋值。

      来看下后台代码吧:

    大段的后台代码
      1 using System;
      2 using System.Windows;
      3 using System.Windows.Controls;
      4 using System.Windows.Input;
      5 
      6 namespace FS.PresentationManagement.Controls
      7 {
      8     /// <summary>
      9     /// 双滑块Slider 
     10     /// By lekko
     11     /// </summary>
     12     public partial class SilderArrange : UserControl
     13     {
     14         #region 私有变量
     15 
     16         private static int _width = 150;  // 拖动条初始宽度
     17         private static int _height = 30;  // 高度
     18         private static int _min = 0;      // 最小值
     19         private static int _max = 100;    // 最大值
     20         private static int _freq = 10;    // 出现刻度的间距
     21 
     22         #endregion
     23 
     24         // 构造函数
     25         public SilderArrange()
     26         {
     27             InitializeComponent();            
     28         }        
     29 
     30         #region 私有属性
     31 
     32         /// <summary>
     33         /// 裁剪矩阵(头)
     34         /// </summary>
     35         private Rect StartRect
     36         {
     37             get { return (Rect)GetValue(StartRectProperty); }
     38             set { SetValue(StartRectProperty, value); }
     39         }
     40         private static readonly DependencyProperty StartRectProperty =
     41             DependencyProperty.Register("StartRect", typeof(Rect), typeof(SilderArrange));
     42 
     43         /// <summary>
     44         /// 裁剪矩阵(尾)
     45         /// </summary>
     46         private Rect EndRect
     47         {
     48             get { return (Rect)GetValue(EndRectProperty); }
     49             set { SetValue(EndRectProperty, value); }
     50         }
     51         private static readonly DependencyProperty EndRectProperty =
     52             DependencyProperty.Register("EndRect", typeof(Rect), typeof(SilderArrange));
     53 
     54         #endregion
     55 
     56         #region 公开依赖属性
     57 
     58         /// <summary>
     59         /// 刻度间距,默认为10
     60         /// </summary>
     61         public int SliderTickFrequency
     62         {
     63             get { return (int)GetValue(SliderTickFrequencyProperty); }
     64             set { SetValue(SliderTickFrequencyProperty, value); }
     65         }
     66         public static readonly DependencyProperty SliderTickFrequencyProperty =
     67             DependencyProperty.Register("SliderTickFrequency", typeof(int), typeof(SilderArrange), new PropertyMetadata(_freq));
     68 
     69         /// <summary>
     70         /// 控件高度,默认为30
     71         /// </summary>
     72         public int SilderHeight
     73         {
     74             get { return (int)GetValue(SilderHeightProperty); }
     75             set { SetValue(SilderHeightProperty, value); }
     76         }
     77         public static readonly DependencyProperty SilderHeightProperty =
     78             DependencyProperty.Register("SilderHeight", typeof(int), typeof(SilderArrange), new PropertyMetadata(_height));
     79 
     80         /// <summary>
     81         /// 拖动条宽度,默认为150
     82         /// </summary>
     83         public int SilderWidth
     84         {
     85             get { return (int)GetValue(SilderWidthProperty); }
     86             set { SetValue(SilderWidthProperty, value); }
     87         }
     88         public static readonly DependencyProperty SilderWidthProperty =
     89             DependencyProperty.Register("SilderWidth", typeof(int), typeof(SilderArrange), new PropertyMetadata(_width));
     90 
     91         /// <summary>
     92         /// 最小值,默认为0
     93         /// </summary>
     94         public int Minimum
     95         {
     96             get { return (int)GetValue(MinimumProperty); }
     97             set { SetValue(MinimumProperty, value); }
     98         }
     99         public static readonly DependencyProperty MinimumProperty =
    100             DependencyProperty.Register("Minimum", typeof(int), typeof(SilderArrange), new PropertyMetadata(_min));
    101 
    102         /// <summary>
    103         /// 最大值,默认为100
    104         /// </summary>
    105         public int Maximum
    106         {
    107             get { return (int)GetValue(MaximumProperty); }
    108             set { SetValue(MaximumProperty, value); }
    109         }
    110         public static readonly DependencyProperty MaximumProperty =
    111             DependencyProperty.Register("Maximum", typeof(int), typeof(SilderArrange), new PropertyMetadata(_max));
    112 
    113         /// <summary>
    114         /// 选中开始值,默认为0
    115         /// </summary>
    116         public int StartValue
    117         {
    118             get { return (int)GetValue(StartValueProperty); }
    119             set { SetValue(StartValueProperty, value); }
    120         }
    121         public static readonly DependencyProperty StartValueProperty =
    122             DependencyProperty.Register("StartValue", typeof(int), typeof(SilderArrange));
    123 
    124         /// <summary>
    125         /// 选中结束值,默认为100
    126         /// </summary>
    127         public int EndValue
    128         {
    129             get { return (int)GetValue(EndValueProperty); }
    130             set { SetValue(EndValueProperty, value); }
    131         }
    132         public static readonly DependencyProperty EndValueProperty =
    133             DependencyProperty.Register("EndValue", typeof(int), typeof(SilderArrange), new PropertyMetadata(_max));
    134 
    135         #endregion
    136 
    137         #region 前台交互
    138 
    139         /// <summary>
    140         /// 对两个拖动条进行裁剪
    141         /// </summary>
    142         private void ClipSilder()
    143         {
    144             int selectedValue = EndValue - StartValue;
    145             int totalValue = Maximum - Minimum;
    146             double sliderClipWidth = SilderWidth * (StartValue - Minimum + selectedValue / 2) / totalValue;
    147             // 对第一个拖动条进行裁剪
    148             StartRect = new Rect(0, 0, sliderClipWidth, SilderHeight);
    149             // 对第二个拖动条进行裁剪
    150             EndRect = new Rect(sliderClipWidth, 0, SilderWidth, SilderHeight);
    151         }        
    152 
    153         /// <summary>
    154         /// 初始化裁剪
    155         /// </summary>
    156         private void UC_Arrange_Loaded(object sender, RoutedEventArgs e)
    157         {
    158             ClipSilder();
    159         }
    160 
    161         private void SL_Bat1_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
    162         {
    163             if (e.NewValue > EndValue)    // 检查值范围
    164                 StartValue = EndValue;    // 超出,重设为最大值
    165             ClipSilder();
    166         }
    167 
    168         private void SL_Bat2_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
    169         {
    170             if (e.NewValue < StartValue)
    171                 EndValue = StartValue;
    172             ClipSilder();
    173         }
    174 
    175         private void TextBox_KeyUp1(object sender, System.Windows.Input.KeyEventArgs e)
    176         {
    177             try
    178             {               
    179                 if (e.Key == Key.Enter)    // 按回车时确认输入
    180                     StartValue = Convert.ToInt32(((TextBox)sender).Text);
    181             }
    182             catch
    183             {
    184             }
    185         }
    186 
    187         private void TextBox_KeyUp2(object sender, KeyEventArgs e)
    188         {
    189             try
    190             {
    191                 if (e.Key == Key.Enter)
    192                     EndValue = Convert.ToInt32(((TextBox)sender).Text);
    193             }
    194             catch
    195             {
    196             }
    197         }       
    198 
    199         #endregion        
    200         
    201     }
    202 }

      这样,在需要使用到这个控件的地方,先在前台代码加上程序集:xmlns:us="clr-namespace:FS.PresentationManagement.Controls",其中“FS.PresentationManagement.Controls”是刚才自定义的控件的命名空间,然后:

    <us:SilderArrange x:Name="SLA_V" SilderWidth="250" Minimum="-50" Maximum="200" />

      就可以了,是不是很方便,呵呵,其实还有不少地方可以改进,不过最少能用了。

    转载请注明原址:http://www.cnblogs.com/lekko/archive/2012/07/23/2604257.html

  • 相关阅读:
    (原)Lazarus 异构平台下多层架构思路、DataSet转换核心代码
    (学)新版动态表单研发,阶段成果3
    (学) 如何将 Oracle 序列 重置 清零 How to reset an Oracle sequence
    (学)XtraReport WebService Print 报错
    (原)三星 i6410 刷机 短信 无法 保存 解决 办法
    (原) Devexpress 汉化包 制作工具、测试程序
    linux下网络配置
    apache自带ab.exe小工具使用小结
    Yii::app()用法小结
    PDO使用小结
  • 原文地址:https://www.cnblogs.com/lekko/p/2604257.html
Copyright © 2011-2022 走看看