SnipperImages(Silverlight DEMO)控件设计之--Slider和ColorSlider

     在上一篇文章中,介绍了CheckBox控件的开发方式,包括xaml和控件逻辑(cs代码控制xaml中UI元素)。
本文所要介绍的Slider控件在xaml上与CheckBox复杂度相似,比较底。而控件逻辑相对要复杂不少,这些
逻辑会在本文中进行介绍。

     好了,开始今天的正文。

     首先看一下这个演示页,如下:



  注:因为我从网上所获得的源码中Slider控件并没有全部开发完,起码在上面所示的垂直Slider只是粗

略的定义了xaml(其中某些值还有错误),而CS代码就少得更多了。本人在原有代码基础上,完成了垂直

Slider的开发,并修正了原有的CS代码中的BUG。


      而该控件的xaml代码如下所示(Slider.xaml):

<ControlTemplate xmlns="http://schemas.microsoft.com/client/2007"
                 xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml" >
  
<Grid x:Name="Part_Root" Width="200" Height="24">
    
<Canvas x:Name="Part_Border" Background="Transparent">
        
<Line x:Name='Part_Line' StrokeThickness="1" Stroke="Blue" X1="4" X2="196" Y1="12"
              Y2
="12"/>
        
<Path x:Name='Part_ThumbHorizontal' Canvas.Top='3' Data='M0,0 L16,0 L8,18z' Fill='Silver'
              Stroke
='Black'/>
        
<Path x:Name='Part_ThumbVertical' Canvas.Left='3' Visibility="Collapsed"
              Data
='M0,0 L18,8 L0,16z' Fill='Silver' Stroke='Black'/>
    
</Canvas>
  
</Grid>
</ControlTemplate>


    从上面代码可以看出,Slider由四个主要元素组成:

   Part_Border:用于绘制背景色(如ColorSlider控件的背景色)

Part_Line:用于绘制滑动的中线

Part_ThumbHorizontal:用于绘制水平滑块

Part_ThumbVertical:用于绘制垂直滑块



  下面这张图标识了各元素在控件中的对应位置和关系:

 

 



      对应上图,下面是ColorSlider的xaml代码:

<ControlTemplate xmlns="http://schemas.microsoft.com/client/2007"
                 xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml" >
<Grid x:Name="Part_Root" Width='200' Height='24'>
    
<Canvas x:Name='Part_Border'>
      
<Canvas.Background>
        
<LinearGradientBrush x:Name="GradientBrush"  StartPoint="0,0" EndPoint="1,0">
          
<GradientStop Color="#FF000000" Offset="0"/>
          
<GradientStop Color="#FFFF0000" Offset="0.143"/>
          
<GradientStop Color="#FF00FF00" Offset="0.286"/>
          
<GradientStop Color="#FF0000FF" Offset="0.429"/>
          
<GradientStop Color="#FF00FFFF" Offset="0.571"/>
          
<GradientStop Color="#FFFF00FF" Offset="0.714"/>
          
<GradientStop Color="#FFFFFF00" Offset="0.857"/>
          
<GradientStop Color="#FFFFFFFF" Offset="1"/>
        
</LinearGradientBrush>
      
</Canvas.Background>
      
<Line x:Name='Part_Line' StrokeThickness="1" Stroke="Blue" X1="4" X2="196" Y1="12" Y2="12"/>
      
<Path x:Name='Part_ThumbHorizontal' Canvas.Top='3' Data='M0,0 L16,0 L8,18z' Fill='Silver'
             Stroke
='Black'/>
      
<Path x:Name='Part_ThumbVertical' Canvas.Left='3' Visibility="Collapsed"
             Data
='M0,0 L18,8 L0,16z' Fill='Silver' Stroke='Black'/>
   
</Canvas>
  
</Grid>
</ControlTemplate>


      说完了xaml,下面开始介绍cs控件逻辑代码。

      首先要说的是一个枚举类型,用于标识滑动方向(垂直或水平):

/// <summary>
/// 滑动条方向类型
/// </summary>
public enum SliderOrientation
{
    
/// <summary>
    
/// 垂直
    
/// </summary>
    Vertical,
    
/// <summary>
    
/// 水平
    
/// </summary>
    Horizontal
}


      而控件的核心代码如下(有关我修改或添加的部分已通过注释说明):


/// <summary>
/// 滑动条控制类
/// </summary>
[TemplatePart(Name = "Part_Root", Type = typeof(Panel))]
[TemplatePart(Name 
= "Part_Border", Type = typeof(FrameworkElement))]
[TemplatePart(Name 
= "Part_ThumbHorizontal", Type = typeof(FrameworkElement))]
[TemplatePart(Name 
= "Part_ThumbVertical", Type = typeof(FrameworkElement))]
[TemplatePart(Name 
= "Part_Line", Type = typeof(FrameworkElement))]
public partial class Slider : Control
{
    
public Slider()
    {
        
string xaml = ResourceHelper.GetTemplate(this.GetType());
        ControlTemplate template 
= (ControlTemplate)XamlReader.Load(xaml);
        
this.Template = template;
        
this.ApplyTemplate();
    }

    
public event EventHandler ValueChanged;

    
/// <summary>
    
/// 值改变时
    
/// </summary>
    protected void OnValueChanged()
    {
        
if (ValueChanged != null)
        {
            
//执行绑定代码
            ValueChanged(thisnew EventArgs());
        }
    }

    
/// <summary>
    
/// 绑定模板元素及相应事件
    
/// </summary>
    public override void OnApplyTemplate()
    {
        Part_Root 
= (Panel)GetTemplateChild("Part_Root");
        Part_Line 
= (Line)GetTemplateChild("Part_Line");
        Part_ThumbHorizontal 
= (FrameworkElement)GetTemplateChild("Part_ThumbHorizontal");
        Part_ThumbVertical 
= (FrameworkElement)GetTemplateChild("Part_ThumbVertical");
        Part_Border 
= (FrameworkElement)GetTemplateChild("Part_Border");

        Part_ThumbHorizontal.MouseLeftButtonDown 
+= new MouseButtonEventHandler(Part_Thumb_MouseLeftButtonDown);
        Part_ThumbHorizontal.MouseMove 
+= new MouseEventHandler(Part_Thumb_MouseMove);
        Part_ThumbHorizontal.MouseLeftButtonUp 
+= new MouseButtonEventHandler(Part_Thumb_MouseLeftButtonUp);
        Part_ThumbVertical.MouseLeftButtonDown 
+= new MouseButtonEventHandler(Part_Thumb_MouseLeftButtonDown);
        Part_ThumbVertical.MouseMove 
+= new MouseEventHandler(Part_Thumb_MouseMove);
        Part_ThumbVertical.MouseLeftButtonUp 
+= new MouseButtonEventHandler(Part_Thumb_MouseLeftButtonUp);
        Part_Root.MouseLeave 
+= new MouseEventHandler(Part_Root_MouseLeave);
        Part_Root.MouseEnter 
+= new MouseEventHandler(Part_Root_MouseEnter);
        Part_Border.MouseLeftButtonDown 
+= new MouseButtonEventHandler(Part_Border_MouseLeftButtonDown);           
    }

    
/// <summary>
    
/// 当鼠标在滑动条(不是滑块)上点击时,将滑块设置到鼠标点击位置
    
/// </summary>
    
/// <param name="sender"></param>
    
/// <param name="e"></param>
    void Part_Border_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        
//当不是滑块时
        if (e.Source != Part_ThumbHorizontal && e.Source != Part_ThumbVertical)
        {
            Point newPos 
= e.GetPosition(Part_Root);
            {
                
if (_orientation == SliderOrientation.Horizontal)
                {
                    Part_ThumbHorizontal.SetValue(Canvas.LeftProperty, Math.Min(newPos.X,
                         Part_Border.ActualWidth 
- Part_ThumbHorizontal.ActualWidth));
                }
                
else
                {
                    Part_ThumbVertical.SetValue(Canvas.TopProperty, Math.Min(newPos.Y,
                         Part_Border.ActualHeight 
- Part_ThumbVertical.ActualHeight));
                }
                
this.OnValueChanged();
            }
        }
    }
    
/// <summary>
    
/// 鼠标进入滑动条区域
    
/// </summary>
    
/// <param name="sender"></param>
    
/// <param name="e"></param>
    void Part_Root_MouseEnter(object sender, MouseEventArgs e)
    {
        
if (hasCapture)
        {
            
if (_orientation == SliderOrientation.Horizontal)
            {
                Part_ThumbHorizontal.CaptureMouse();
            }
            
else
            {
                Part_ThumbVertical.CaptureMouse();
            }
        }
        
else
        {
            _mouseDownValue 
= -1;
        }
    }

    
/// <summary>
    
/// 鼠标离开滑动条区域
    
/// </summary>
    
/// <param name="sender"></param>
    
/// <param name="e"></param>
    void Part_Root_MouseLeave(object sender, MouseEventArgs e)
    {
        
if (_orientation == SliderOrientation.Horizontal)
        {
            Part_ThumbHorizontal.ReleaseMouseCapture();
        }
        
else
        {
            Part_ThumbVertical.ReleaseMouseCapture();
        }
    }
    
/// <summary>
    
/// 鼠标按下滑动块
    
/// </summary>
    
/// <param name="sender"></param>
    
/// <param name="e"></param>
    void Part_Thumb_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        FrameworkElement thumb 
= (FrameworkElement)sender;
        
//在当前滑动块上设置“鼠标捕获”
        thumb.CaptureMouse();
        hasCapture 
= true;
        _thumbMouseDown 
= e.GetPosition(Part_Root);
        
        
if (_orientation == SliderOrientation.Horizontal)//当为水平方向时
        {
            
//获取滑动块的“左”值属性
            _mouseDownValue = (double)thumb.GetValue(Canvas.LeftProperty);
        }
        
else
        {
            
//获取滑动块的“顶”值属性
            _mouseDownValue = (double)thumb.GetValue(Canvas.TopProperty);
        }
    }

    
/// <summary>
    
/// 鼠标拖动滑动块移动
    
/// </summary>
    
/// <param name="sender"></param>
    
/// <param name="e"></param>
    void Part_Thumb_MouseMove(object sender, MouseEventArgs e)
    {
        FrameworkElement thumb 
= (FrameworkElement)sender;
        Point newPos 
= e.GetPosition(Part_Root);
        
if (_orientation == SliderOrientation.Horizontal)
        {
            
double newX = newPos.X - _thumbMouseDown.X + _mouseDownValue;
            
if (_mouseDownValue != -1 &&
                newX 
<= Part_Border.ActualWidth - 8 &&
                newX 
>= -8)
            {
                thumb.SetValue(Canvas.LeftProperty, newX);
//仅在水平方向上移动
                this.OnValueChanged();
            }
        }
        
else
        {
            
double newY = newPos.Y - _thumbMouseDown.Y + _mouseDownValue;
            
if (_mouseDownValue != -1 &&
                newY 
<= Part_Border.ActualHeight - 8 &&
                newY 
>= -8)
            {
                thumb.SetValue(Canvas.TopProperty, newY);
//仅在垂直方向上移动
                this.OnValueChanged();
            }
        }
    }

    
/// <summary>
    
/// 鼠标拖动结束
    
/// </summary>
    
/// <param name="sender"></param>
    
/// <param name="e"></param>
    void Part_Thumb_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        FrameworkElement thumb 
= (FrameworkElement)sender;
        _mouseDownValue 
= -1;
        thumb.ReleaseMouseCapture();
        hasCapture 
= false;
    }

    
/// <summary>
    
/// 设置滑动条的宽
    
/// </summary>
    public double SliderWidth
    {
        
get { return Part_Root.Width; }
        
set
        {
            
if (_orientation == SliderOrientation.Horizontal)
            {
                
//水平方向上设置
                Part_Line.X2 = value;
                Part_Root.Width 
= value;
            }
            
else
            {
                
//获取Slider.xaml中的相应属性配置
                Part_Line.X1 = Part_Line.X2 = value / 2d;
                Part_ThumbVertical.SetValue(Canvas.LeftProperty, value 
/ 2d - Part_ThumbVertical.ActualWidth / 2d);
            }
        }
    }

    
/// <summary>
    
/// 设置滑动条的高度
    
/// </summary>
    public double SliderHeight
    {
        
get { return Part_Root.Height; }
        
set
        {
            
if (_orientation == SliderOrientation.Horizontal)
            {
                
//获取Slider.xaml中的相应属性配置
                Part_Line.Y1 = Part_Line.Y2 = value / 2d;
                Part_ThumbHorizontal.SetValue(Canvas.TopProperty, value 
/ 2d - Part_ThumbHorizontal.ActualHeight / 2d);
            }
            
else
            {
                
//垂直方向上设置
                Part_Line.Y2 = value;
                Part_Root.Height 
= value;
            }
        }
    }

    
/// <summary>
    
/// 获取或设置滑动条的当前值
    
/// </summary>
    public double Value
    {
        
get
        {
            
if (_orientation == SliderOrientation.Horizontal)
            {
                
double val = (double)Part_ThumbHorizontal.GetValue(Canvas.LeftProperty) / (Part_Root.ActualWidth - 8);
                val 
= Math.Max(0d, val);
                val 
= Math.Min(val, 1d);
                
return val;
            }
            
else
            {
                
double val = (double)Part_ThumbVertical.GetValue(Canvas.TopProperty) / (Part_Root.ActualHeight - 8);
                val 
= Math.Max(0d, val);
                val 
= Math.Min(val, 1d);
                
return val;
            }
        }
        
set
        {
            
if (_orientation == SliderOrientation.Horizontal)
            {
                Part_ThumbHorizontal.SetValue(Canvas.LeftProperty, value 
* (Part_Root.Width - 8));
            }
            
else
            {
                Part_ThumbVertical.SetValue(Canvas.TopProperty, value 
* (Part_Root.Height - 8));
            }
        }
    }

    
/// <summary>
    
/// 获取或设置滑动条的方向,参见SliderOrientation
    
/// </summary>
    public  SliderOrientation Orientation
    {
        
get { return _orientation; }
        
set
        {
            _orientation 
= value;
            
if (_orientation == SliderOrientation.Horizontal)
            {
                Part_ThumbVertical.Visibility 
= Visibility.Collapsed;
                Part_ThumbHorizontal.Visibility 
= Visibility.Visible;
                Part_Line.Y1 
= Part_Line.Y2 = Part_Root.Height / 2d;
                Part_Line.X1 
= 0d;
                Part_Line.X2 
= Part_Root.Width;
            }
            
else
            {
                
//注:此处代码为本人所加,用于当为垂直方向时,交换Width与Height的值
                double temp = Part_Root.Width;
                Part_Root.Width 
= Part_Root.Height;
                Part_Root.Height 
= temp;                    

                Part_ThumbHorizontal.Visibility 
= Visibility.Collapsed;
                Part_ThumbVertical.Visibility 
= Visibility.Visible;
                Part_Line.X1 
= Part_Line.X2 = Part_Root.Width / 2d;
                Part_Line.Y1 
= 0d;
                Part_Line.Y2 
= Part_Root.Height;
            }
        }
    }

    
#region UI元素声明
    
protected Panel Part_Root;
    
protected Line Part_Line;
    
protected FrameworkElement Part_Border, Part_ThumbVertical, Part_ThumbHorizontal;
    
#endregion

    
protected Point _thumbMouseDown;
    
protected double _mouseDownValue = -1;
    
protected bool hasCapture = false;
    
protected SliderOrientation _orientation = SliderOrientation.Horizontal;
}


       下面代介绍的是ColorSlider控件的控件逻辑cs文件(详情看注释):

/// <summary>
/// 颜色滑动条控制
/// </summary>
public partial class ColorSlider : Slider
{
    
public ColorSlider()
    {
        
string xaml = ResourceHelper.GetTemplate(this.GetType());
        ControlTemplate template 
= (ControlTemplate)XamlReader.Load(xaml);
        
this.Template = template;
        
base.ApplyTemplate();
    }
    
/// <summary>
    
/// 该方法为本人所加,用户当滑动条方向为“垂直”时,重新设置“GradientBrush”的“EndPoint”属性
    
/// </summary>
    public new SliderOrientation Orientation
    {
        
get { return base.Orientation; }
        
set
        {
            
base.Orientation = value;
            
//当为垂直方向时
            if (value == SliderOrientation.Vertical)
            {
                ((LinearGradientBrush)GetTemplateChild(
"GradientBrush")).EndPoint = new Point(01);
            }               
        }
    }
    

/// <summary>
/// 获取颜色值
/// </summary>
/// <returns></returns>
    public Color GetColor()
    {
        
return this.GetColor(255);
    }

    
/// <summary>
    
/// 将滑动条值(Value)转换为ARGB 颜色值并返回
    
/// </summary>
    
/// <param name="alpha">alpha通道,该值介于0到255</param>
    
/// <returns>ARGB 颜色值</returns>
    public Color GetColor(byte alpha)
    {
        Color color;
        
double value = this.Value;

        
// 将滑动条的值转换为 ARGB 颜色值
        if (value < 0.143d)
        {
            color 
= Color.FromArgb(alpha, (byte)Math.Floor((value * 256d) / 0.143d), 00);
        }
        
else if (value < 0.286d)
        {
            color 
= Color.FromArgb(alpha, (byte)Math.Floor(256d * (0.286d - value) / 0.143d), 
                              (
byte)Math.Floor(256d * (value - 0.143d/ 0.143d), 0);
        }
        
else if (value < 0.429)
        {
            color 
= Color.FromArgb(alpha, 0, (byte)Math.Floor(256d * (0.429d - value) / 0.143d), 
                              (
byte)Math.Floor(256d * (value - 0.286d/ 0.143d));
        }
        
else if (value < 0.571)
        {
            color 
= Color.FromArgb(alpha, 0, (byte)Math.Floor(256d*(value-0.429d)/0.143d), 255);
        }
        
else if (value < 0.714)
        {
            color 
= Color.FromArgb(alpha, (byte)Math.Floor(256d * (value - 0.571d/ 0.143d), 
                             (
byte)Math.Floor(256d * (0.714d - value) / 0.143d), 255);
        }
        
else if (value < 0.857)
        {
            color 
= Color.FromArgb(alpha, 255, (byte)Math.Floor(256d * (value - 0.714d/ 0.143d), 
                             (
byte)Math.Floor(256d * (0.857d - value) / 0.143d));
        }
        
else
        {
            color 
= Color.FromArgb(alpha, 255255, (byte)Math.Floor(256d * (value - 0.857d/ 0.143d));
        }
        
return color;
    }
}


      接着再来看一下如何使用这两个控件(也就是本文第一张图所演示的效果),其page逻辑代码如下:

public partial class Page2 : UserControl
{
 
public Page2()
     {
            InitializeComponent();
            
            
            
#region Slider测试代码,加载图片并添加演示缩放旋转的Transform

            
string baseUri = Application.Current.Host.Source.AbsoluteUri.Substring(0
                                    Application.Current.Host.Source.AbsoluteUri.LastIndexOf(
"/"));
            currentImage.SetValue(Image.SourceProperty, 
new BitmapImage(
                                     
new Uri(String.Concat(baseUri, "/../Images/j0433157.jpg"))));
            TransformGroup transforms 
= new TransformGroup();
            transforms.Children.Add(
new ScaleTransform());
            transforms.Children.Add(
new RotateTransform());
            currentImage.RenderTransform 
= transforms;
            currentImage.RenderTransformOrigin 
= new Point(0.50.5);

            
#endregion

    }

    
#region Slider示例代码
    
void ColorSlider_ValueChanged(object sender, EventArgs e)
    { 
       
//水平Slider设置背景色
        SliderPanel.Background = new SolidColorBrush(ColorSlider.GetColor());
    }

    
void ColorSlider2_ValueChanged(object sender, EventArgs e)
    {
      
//垂直Slider设置背景色
        SliderPanel2.Background = new SolidColorBrush(ColorSlider2.GetColor());
    }

    
private void opacitySlider_ValueChanged(object sender, EventArgs e)
    { 
      
//设置图像的Opacity属性
        currentImage.Opacity = 1d - opacitySlider.Value;
    }

    
    
private void transformSlider_ValueChanged(object sender, EventArgs e)
    {
      
//设置旋转属性
        ((RotateTransform)((TransformGroup)currentImage.RenderTransform).Children[1]).Angle = 
                                                     (transformSlider.Value 
- 0.5d* 720d;
//设置缩放属性
        ((ScaleTransform)((TransformGroup)currentImage.RenderTransform).Children[0]).ScaleX = 
                                                     transformSlider.Value 
* 2d;
        ((ScaleTransform)((TransformGroup)currentImage.RenderTransform).Children[
0]).ScaleY = 
                                                     transformSlider.Value 
* 2d;
    }
    
#endregion
}


     好了,今天的内容就先到这里了。

     tag:silverlight,slider,colorslider,imagesnipper

     作者:代震军,daizhj

     原文链接:http://www.cnblogs.com/daizhj/archive/2008/09/04/1284228.html

     源码下载,请点击这里:)
posted @ 2008-09-12 11:28  代震军  阅读(3792)  评论(4编辑  收藏  举报