sl简单自定义win窗体控件

 
   相信大家接触过不少win窗体控件ChildWin子窗口就的sl自带的一个

 而且网上也有很多类似的控件,而今天我和大家分享下自己制作个win窗体控件,希望对初学sl的朋友在学习自定义控件时有帮助。
     首先先明确下两个概念用户控件和模板化控件。
    用户控件是继承UserControl而来的控件,由于UserControl不支持模板,所以它只能用于组合现有控件件而不能用于设计可定制外观的控件。
     模板化控件是继承自ContentControl, Control等支持模板的而来的控件,ContentControl是继承自Control 他只能有一个可视化根元素,这一点和UserControl一样。而我们这次就是要用ContentControl实现我们的Win窗体控件。
   下面大家先看下ContentControl的模板
 
1.   <Style TargetType="ContentControl"> 
2.         <Setter Property="Foreground" Value="#FF000000"/> 
3.         <Setter Property="HorizontalContentAlignment" Value="Left"/> 
4.         <Setter Property="VerticalContentAlignment" Value="Top"/> 
5.         <Setter Property="Template"> 
6.             <Setter.Value> 
7.                 <ControlTemplate TargetType="ContentControl"> 
8.                     <ContentPresenter 
9.                         Content="{TemplateBinding Content}" 
10.                       ContentTemplate="{TemplateBinding ContentTemplate}" 
11.                       Cursor="{TemplateBinding Cursor}" 
12.                       Margin="{TemplateBinding ;Padding}" 
13.                       HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
14.                       VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/> 
15.               </ControlTemplate> 
16.           </Setter.Value> 
17.       </Setter> 
18.   </Style> 
19.  
20.  
         在ContentControl的模板中只有一个ContentPresenter来定制ContentControl的内容区域
用TemplateBinding将模板属性绑定到控件公开的属性属性这里就不做介绍了有兴趣的朋友可以去看下sl的文档。
       接下来开始我们的控件制作之旅,在VS或Blend新建个项目
       由于我这是使用VS在模板里编辑外观和麻烦所以先在MainPage里设计好外观再加到模板中
        首先拖个矩形到界面调整属性使它填充界面(去掉长宽和Margin等)加上圆角
      
1.   <Rectangle x:Name="BackRect" Fill="#932323B7" RadiusX="5" RadiusY="5" Grid.RowSpan="4" Grid.ColumnSpan="3"/> 
 
 
接下来再拖个矩形到界面调整下使它
 
1.   <Rectangle Name="Win_Content" Grid.Row="2" Grid.Column="1" Fill="white"/> 
 
对接着对主界面Grid分行分列
 
1.   <Grid.ColumnDefinitions> 
2.               <ColumnDefinition Width="5*" /> 
3.               <ColumnDefinition Width="390*" /> 
4.               <ColumnDefinition Width="5*" /> 
5.           </Grid.ColumnDefinitions> 
6.           <Grid.RowDefinitions> 
7.               <RowDefinition Height="5*" /> 
8.               <RowDefinition Height="15*" /> 
9.               <RowDefinition Height="275*" /> 
10.             <RowDefinition Height="5*" /> 
11. </Grid.RowDefinitions> 
 
接下来拖曳五个矩形到界面
 
1.   <Rectangle Grid.Column="1" Name="Win_Move" Fill="#932323B7" Grid.RowSpan="2"/> 
2.    
3.           <Rectangle Grid.Row="2" Grid.Column="2" x:Name="Side_Right" Cursor="SizeWE"></Rectangle> 
4.           <Rectangle Grid.Row="2" x:Name="Side_Left" Cursor="SizeWE"></Rectangle> 
5.           <Rectangle Grid.Row="3" Grid.Column="1" x:Name="Side_Botton" Cursor="SizeNS"></Rectangle> 
6.           <Rectangle Grid.Column="1" x:Name="Side_Top" Cursor="SizeNS"></Rectangle> 
 
大家可以看到后面是个矩形我设置了Cursor并把它们放在是个边缘上,这个是为后面实现窗体拉伸用的
 接着拖曳个TextBlock
1.   <TextBlock Grid.Column="1" Grid.Row="1" Name="Win_Title" HorizontalAlignment="Left"  Grid.RowSpan="1"/> 
 
这是为了实现win窗体的标题
接着拖个Grid并
设置属性
在里面添加三个按钮
 
 
1.   <Grid Grid.Column="1" Grid.RowSpan="2"  HorizontalAlignment="Right"  Name="ButtonGroup"  Width="75"> 
2.               <Grid.ColumnDefinitions> 
3.                   <ColumnDefinition Width="20*" /> 
4.                   <ColumnDefinition Width="20*" /> 
5.                   <ColumnDefinition Width="20*" /> 
6.               </Grid.ColumnDefinitions> 
7.               <Button Style="{StaticResource btnMinimizeStyle}"></Button> 
8.               <Button Grid.Column="1" Style="{StaticResource btnWindowedStyle}"></Button> 
9.               <Button Grid.Column="2" Style="{StaticResource btnCloseStyle}"></Button> 
10.         </Grid> 
本人没啥艺术天赋就到网上随便找了三个按钮样式!!!!!!!!!!!!!!!
 
 
 
 
接着实现win窗体的阴影效果
 
这个也很简单只要使用Effect就能实现
 
先复制一下背景矩形的xaml
然后加Effect
 
1.   <Rectangle Fill="Black" RadiusX="5" RadiusY="5" Grid.RowSpan="4" Grid.ColumnSpan="3"> 
2.               <Rectangle.Effect> 
3.                   <BlurEffect Radius="9"></BlurEffect> 
4.               </Rectangle.Effect> 
5.           </Rectangle> 
6.           <Rectangle x:Name="BackRect" Fill="#932323B7" RadiusX="5" RadiusY="5" Grid.RowSpan="4" Grid.ColumnSpan="3"> 
7.               <!--<Rectangle.Effect> 
8.                   <DropShadowEffect></DropShadowEffect> 
9.               </Rectangle.Effect>--> 
10.         </Rectangle> 
 
 
现在窗体的基本外观已经完成
在界面里加个ContentPresenter
 
1.   <ContentPresenter Grid.Row="2" Grid.Column="1"></ContentPresenter> 
现在项目里添加个模板控件把cs文件里的基类改为ContentControl
并设置ContentPresenter属性
 
1.   <ContentPresenter Grid.Row="2" Grid.Column="1" Content="{TemplateBinding Content}" 
2.                                            HorizontalAlignment="{TemplateBinding HorizontalAlignment}"   
3.                                            VerticalAlignment="{TemplateBinding VerticalAlignment}" 
4.                                            ContentTemplate="{TemplateBinding ContentTemplate}" 
5.                                            Cursor="{TemplateBinding Cursor}" 
6.                                            Margin="{TemplateBinding ;Padding}"></ContentPresenter> 
接着你可以在编译项目拖曳个Win窗体控件或新建个Win窗体控件为基类的控件
 
1.   <my:WInControl x:Class="anyePath.SilverlightControl1" 
2.       xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
3.       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
4.       xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
5.       xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
6.       mc:Ignorable="d" 
7.       d:DesignHeight="300" d:DesignWidth="400" xmlns:my="clr-namespace:anyePath" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"> 
8.         
9.       <Grid x:Name="LayoutRoot"> 
10.         <Button Content="Button" Height="64" HorizontalAlignment="Left" Margin="68,48,0,0" Name="button1" VerticalAlignment="Top" Width="119" /> 
11.         <RadioButton Content="RadioButton" Height="44" HorizontalAlignment="Left" Margin="53,152,0,0" Name="radioButton1" VerticalAlignment="Top" Width="88" /> 
12.         <ComboBox Height="47" HorizontalAlignment="Left" Margin="218,18,0,0" Name="comboBox1" VerticalAlignment="Top" Width="135" /> 
13.     </Grid> 
14. </my:WInControl> 
 
这里先讲到这我们已经完成了控件的基本外观
在下篇文章里我们就要为窗体添加功能
如移动拉伸标题依赖属性最大化最小化等等 的设置
这章就到这里希望对大家有帮助!!!!!!
  
       在上一篇文章里我们完成了Win窗体的基本外观,但仅仅只有个外观我想大家都不会满意,那在我们

就开始给窗体添加功能。

在这为了简化步骤,就以父容器为Canvas考虑,由于他是绝对布局的所以实现移动较方便,大家如果要是控件的使用范围些 可以去试试用平移变换实现窗体移动。

首先 还是先明确下一些基础点,由于 窗体的外观是在模板里定义的,所以于窗体有关的部件我们不能直接访问,不过访问的方法有好几种,我在这介绍两种。

1.我们可以在那些模板里的部件加上Loaded事件,再在这个事件的处理函数里把,这个部件的引用保存下来。

2.是重写OnApplyTemplate方法在这个方法里调用GetTemplateChild获得部件引用。

我这是利用第二种方法,好现在开始实现功能

  1. public override void OnApplyTemplate()
  2. {
  3. base.OnApplyTemplate();
  • TitleC = GetTemplateChild("Win_Title") as TextBlock;//是呈现窗体的TextBlock
  • BackImage = GetTemplateChild("BackRect") as Rectangle;//是背景矩形
  • TitleC.Text = Title;//Title是窗体标题的依赖属性
  • //窗体顶部矩形 用于移动矩形
  • (GetTemplateChild("Win_Move") as Rectangle).MouseLeftButtonDown += new MouseButtonEventHandler(WInControl_MouseLeftButtonDown);
  • //窗体四边的矩形,还记得吗上篇文章 我给他设置Cursor属性这就是为了实现 鼠标移动到窗体边缘的变化 主要要把那四个矩形的背景不能透明,即使0.05也行 就不能透明
  • (GetTemplateChild("Side_Right") as Rectangle).MouseLeftButtonDown+=new MouseButtonEventHandler(WInControl_MouseLeftButtonDown);
  • (GetTemplateChild("Side_Left") as Rectangle).MouseLeftButtonDown += new MouseButtonEventHandler(WInControl_MouseLeftButtonDown);
  • (GetTemplateChild("Side_Top") as Rectangle).MouseLeftButtonDown += new MouseButtonEventHandler(WInControl_MouseLeftButtonDown);
  • (GetTemplateChild("Side_Botton") as Rectangle).MouseLeftButtonDown += new MouseButtonEventHandler(WInControl_MouseLeftButtonDown);
  • //就是窗体上的那三个按钮
  • (GetTemplateChild("MinB") as Button).Click +=new RoutedEventHandler(WInControl_Click);
  • (GetTemplateChild("MaxB") as Button).Click +=new RoutedEventHandler(WInControl_Click);
  • (GetTemplateChild("CloseB") as Button).Click += new RoutedEventHandler(WInControl_Click);
  • }
  • 这里就是移动窗体和尺寸拉伸的 代码

    protected void WInControl_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)

    1. {
    2. Rectangle rect = sender as Rectangle;
    3. rect.MouseMove += new MouseEventHandler(rect_MouseMove);
    4. rect.MouseLeftButtonUp += new MouseButtonEventHandler(rect_MouseLeftButtonUp);
    5. rect.CaptureMouse();
    6. LastPoint = e.GetPosition(Owner);
    7. // 这里就注册鼠标移动事件 和 弹起事件
    8. }
    9. void rect_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    10. {
    11. Rectangle rect = sender as Rectangle;
    12. rect.MouseMove -= rect_MouseMove;
    13. rect.MouseLeftButtonUp -= rect_MouseLeftButtonUp;
    14. rect.ReleaseMouseCapture();
    15. //这里也没什么好说
    16. }
    17. protected void rect_MouseMove(object sender, MouseEventArgs e)
    18. {
    19. Rectangle rect = sender as Rectangle;
    20. Point p = e.GetPosition(Owner);
    21. //这里按照Name判断执行什么操作
    22. switch (rect.Name)
    23. {
    24. case "Win_Move": MoveWin(p); break;
    25. case "Side_Right": ChangeRightWin(p); break;
    26. case "Side_Left": ChangeLeftWin(p); break;
    27. case "Side_Top": ChangeTopWin(p); break;
    28. case "Side_Botton": ChangeBottomWIn(p); break;
    29. }
    30. }
    31. //而这里是移动的主要逻辑 如果大家做过拖曳控件的功能就非常简单
    32. public void MoveWin(Point e)
    33. {  //LastPoint在鼠标点击事件里赋值 记录了上一个事件里鼠标的位置
    34. // 而这用这事鼠标的位置减去上一时刻的鼠标位置 然后再移动窗体这个差值
    35. //这两个判断语句是防止窗体整个移界面
    36. Point D_point = new Point(e.X - LastPoint.X, e.Y - LastPoint.Y);
    37. if (!(Canvas.GetTop(this) <= 0 && D_point.Y <= 0))
    38. {
    39. if (!(Canvas.GetTop(this) > Owner.ActualHeight && D_point.Y >= 0))
    40. {
    41. Canvas.SetLeft(this, Canvas.GetLeft(this) + D_point.X);
    42. Canvas.SetTop(this, Canvas.GetTop(this) + D_point.Y);
    43. //再保存位置
    44. LastPoint = e;
    45. }
    46. }
    47. }
    48. //下面四个方法是改变窗体大小的
    49. void ChangeBottomWIn(Point e)
    50. {  //这个是底边拉伸窗体 也很好理解 就是计算出 当鼠标点下 后每次Move的差值 在把这个差值加到窗体高度上
    51. double M_mun = e.Y - Canvas.GetTop(this) - this.Height;
    52. if (this.Height >= 100 || M_mun > 0)
    53. this.Height += M_mun;
    54. }
    55. void ChangeTopWin(Point e)
    56. {            //这是顶部拉伸的代码 但这不能简单把移动差值加到 控件高度上
    57. //这样会造成向上拉伸 向下变长的现象 我们必须先向上移动控件 这个差值再加
    58. double M_mun = Canvas.GetTop(this) - e.Y;
    59. if(this.Height >= 100 || M_mun >0)
    60. this.Height += M_mun;
    61. LastPoint = e;
    62. Canvas.SetTop(this, LastPoint.Y);
    63. }
    64. //接下来的左边和右边就不讲 原理和上面一样
    65. void ChangeLeftWin(Point e)
    66. {
    67. double M_mun = Canvas.GetLeft(this) - e.X;
    68. if (this.Width >= 100 || M_mun > 0)
    69. this.Width += M_mun;
    70. LastPoint = e;
    71. Canvas.SetLeft(this, LastPoint.X);
    72. }
    73. void ChangeRightWin(Point e)
    74. {
    75. double M_mun = e.X - Canvas.GetLeft(this) - this.Width;
    76. if (this.Width >= 100 || M_mun > 0)
    77. this.Width += M_mun;
    78. }

    接下来是实现最大化的功能

    接着看代码

    1. public static readonly DependencyProperty IsMaxmunProperty = DependencyProperty.Register("IsMaxmun", typeof(bool), typeof(WInControl), new PropertyMetadata(false, onIsMaxmunChange)); //这是定义的最大化的依赖属性说是最大化 其实是最大化和窗口化
    1. public bool IsMaxmun//最大化
    2. {
    3. get { return (bool)this.GetValue(IsMaxmunProperty); }
    4. set { this.SetValue(IsMaxmunProperty, value); }
    5. }
    1. public static void onIsMaxmunChange(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    2. {
    3. WInControl This = sender as WInControl;
    4. if (This.IsMaxmun == true)
    5. This.ToMaxmun();
    6. else
    7. This.ToMinnormal();
    8. }
    1. protected virtual void ToMaxmun()
    2. {  //把窗体高和宽保存起来 再把窗体设置成与父容器 这里有个Owner是用来设置父容器引用
    3. //大家也可 用Parent属性 他就是在可视树上的父节点
    4. LastPoint.X = Canvas.GetLeft(this);
    5. LastPoint.Y = Canvas.GetTop(this);
    6. LastWinSize.Width = this.Width;
    7. LastWinSize.Height = this.Height;
    8. Canvas.SetLeft(this, 0);
    9. Canvas.SetTop(this, 0);
    10. this.Height = (Owner).RenderSize.Height;
    11. this.Width = (Owner).RenderSize.Width;
    12. }
    13. protected virtual void ToMinnormal()
    14. {  //这里就是还原窗体
    15. Canvas.SetLeft(this, LastPoint.X);
    16. Canvas.SetTop(this, LastPoint.Y);
    17. this.Height = LastWinSize.Height;
    18. this.Width = LastWinSize.Width;
    19. }

    这就是最大化和窗口化功能 还有一点在最大化时大家要 移除那几个矩形的鼠标点击事件 再在

    窗口化添加这个事件 最小化就留给大家自己考虑。

    1. public static readonly DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(string), typeof(WInControl), new PropertyMetadata(string.Empty, OnTitleChanged));

    这个是窗体标题

    1. public string Title
    2. {
    3. get { return (string)GetValue(TitleProperty); }
    4. set { SetValue(TitleProperty, value); }
    5. }
    1. public static void OnTitleChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    2. {
    3. WInControl This = sender as WInControl;
    4. if (This.TitleC != null)
    5. This.TitleC.Text = This.Title;
    6. }
    这里有一点要注意 由于这个方法比较早调用 而 TitleC没有设置引用 所以要判断下是否为null

    这里一部分基本功能已经完成了

    不过有两个重要的功能就是关闭 和打开窗体

    这里的repeat和repeat2是防止动画被多次设定

    动画已经在资源里

    只是没有设定作用对象

    1. public override void Close()
    2. {
    3. Storyboard app = Resources["_disappear"] as Storyboard;
    4. if (repeat == false)
    5. {
    6. foreach (var item in app.Children)
    7. {
    8. Storyboard.SetTarget(item, this);
    9. }
    10. repeat = true;
    11. }
    12. app.Begin();
    13. }
    14. public override void Open()
    15. {
    16. Storyboard app = Resources["_appear"] as Storyboard;
    17. this.Visibility = Visibility.Visible;
    18. if (repeat2 == false)
    19. {
    20. foreach (var item in app.Children)
    21. {
    22. Storyboard.SetTarget(item, this);
    23. }
    24. repeat2 = true;
    25. }
    26. app.Begin();
    27. }

    就这样就可以实现关闭和打开的功能

    而且动画由你自己设定

    这里先讲到这里 可能有很多不足 但免免强强一个自己写的win窗体控件算完成了

    对于那些sl老手可能没什么

    但我希望对sl初学的朋友有帮助

    还请大家多提意见相互学习 Demo我整理下晚点发上来

    希望大家这个基础上继续加强!!!!!!!!!!

    演示地址http://anye6488-001-site1.site4future.com/anyePath.web/anyePathTestPage1.html

注:本文转自http://dingtao-wgs.blog.163.com/blog/static/502607142010101754018734/,仅供学习之用。

(转)sl简单自定义win窗体控件的更多相关文章

  1. jquery和css自定义video播放控件

    下面介绍一下通过jquery和css自定义video播放控件. Html5 Video是现在html5最流行的功能之一,得到了大多数最新版本的浏览器支持.包括IE9,也是如此.不同的浏览器提供了不同的 ...

  2. 如何在多线程中调用winform窗体控件

    由于 Windows 窗体控件本质上不是线程安全的.因此如果有两个或多个线程适度操作某一控件的状态(set value),则可能会迫使该控件进入一种不一致的状态.还可能出现其他与线程相关的 bug,包 ...

  3. jQ效果:jQuery和css自定义video播放控件

    下面介绍一下通过jquery和css自定义video播放控件. Html5 Video是现在html5最流行的功能之一,得到了大多数最新版本的浏览器支持.包括IE9,也是如此.不同的浏览器提供了不同的 ...

  4. QT 窗体控件的透明度设置(三种方法)

    整个窗体 当设置QT的窗体(QMainWindow, QDialog)时,直接用 targetForm->setWindowOpacity()   函数即可实现,效果为窗体及窗体内所有控件都透明 ...

  5. C# WinForm自定义通用分页控件

    大家好,前几天因工作需要要开发一个基于WinForm的小程序.其中要用到分页,最开始的想法找个第三方的dll用一下,但是后来想了想觉得不如自己写一个玩一下 之前的web开发中有各式各样的列表组件基本都 ...

  6. WPF教程十一:简单了解并使用控件模板

    WPF教程十一:简单了解并使用控件模板 这一章梳理控件模板,每个WPF控件都设计成无外观的,但是行为设计上是不允许改变的,比如使用Button的控件时,按钮提供了能被点击的内容,那么自由的改变控件外观 ...

  7. kettle系列-[KettleUtil]kettle插件,类似kettle的自定义java类控件

    该kettle插件功能类似kettle现有的定义java类插件,自定java类插件主要是支持在kettle中直接编写java代码实现自定特殊功能,而本控件主要是将自定义代码转移到jar包,就是说自定义 ...

  8. winform窗体控件(全)

    回顾跟补充下除了昨天那常用6个其他的winform窗体控件作用 1:Button:按钮 (1)AutoSize:如果是True的情况下,内容将会撑开:False的话会另起一行 (2)Enabled: ...

  9. WPF自定义控件与样式(8)-ComboBox与自定义多选控件MultComboBox

    一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接. 本文主要内容: 下拉选 ...

随机推荐

  1. 01 LabVIEW的类中各个Scope的范围

    范例地址: D:\Program Files (x86)\National Instruments\LabVIEW 2015\examples\Object-Oriented Programming\ ...

  2. SMTP Error: Could not connect to SMTP host

    PHPMailer是一个非常棒的开源邮件类,使用也非常简单,但是对于虚拟主机来说,往往要受到各种限制.刚才我在虚拟主机上使用PHPMailer就遇到一个“SMTP Error: Could not c ...

  3. 贪吃蛇的java代码分析(二)

    代码剖析 贪吃蛇是一款十分经典的小游戏,对初入coding的朋友来说,拿贪吃蛇这样一个案例来练手十分合适,并不高的难度和成功后的成就感都是学习所必须的.下面我将依照我当时的思路,来逐步分析实现的整个过 ...

  4. How to reset password for unknow root

    1. Click "e" when entering the grub 2. Add option " init=/bin/sh" to linux line. ...

  5. 视图UIView的大小和位置属性详解

    UIView类中定义了三个属性,分别是frame.bounds与center属性: IKit中的坐标系X轴正方向为水平向右,Y轴正方向为竖直向下. frame属性指的是视图在其父视图坐标系中的位置与尺 ...

  6. 转摘 MySQL扫盲篇

    一下文章摘自:http://www.jellythink.com/archives/636 MySQL扫盲篇 2014-09-15 分类:MySQL / 数据库 阅读(1412) 评论(1)  为什么 ...

  7. UNIX中的文件类型

    Unix的文件类型信息包含在stat结构的st_mode成员中可以用宏确定文件类型: 普通文件(S_ISREG()):包含某种形式数据的常用文件类型 目录文件(S_ISDIR()):这种文件包含其他文 ...

  8. CXF Spring开发WebService,基于SOAP和REST方式 【转】

    官网示例 http://cxf.apache.org/docs/writing-a-service-with-spring.html http://cxf.apache.org/docs/jax-rs ...

  9. C#类继承和接口继承时一些模棱两可的问题[转]

    原文地址:http://www.cnblogs.com/harleyhu/archive/2012/11/29/2794809.html 1.在father定义的方法若含有virtual关键字,chi ...

  10. React Native IOS源码初探

    原文链接 http://www.open-open.com/lib/view/open1465637638193.html 每个项目都有一个入口,然后进行初始化操作,React Native 也不例外 ...