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. 兼容IE浏览器的js浏览器全屏代码

    众所周知,IE是个奇葩的浏览器,但是由于用户量很大,开发者还是不得不为IE考虑一下,于是,各种浏览器相关的操作,都要多一个特别的判断——专门针对IE浏览器的判断,这里的全屏也不例外.看代码: func ...

  2. 【emWin】例程三:显示方向的切换

    实验指导书及代码包下载: http://pan.baidu.com/s/1pK9o0xP

  3. PostGr-SQL 基本概念

    http://wenjiesu.iteye.com/blog/801129 [什么是schema?] 究竟什么是schema?这个问题困扰了我很久. 我们只讨论数据库中的schema,而不讨论XML中 ...

  4. OpenGL中实现双缓冲技术

    在OpenGL中实现双缓冲技术的一种简单方法: 1.在调用glutInitDisplayMode函数时, 开启GLUT_DOUBLE,即glutInitDisplayMode(GLUT_RGB | G ...

  5. Android高级之十二讲之如何降低应用内存消耗

    安卓应用的内存往往是有限的,从开始的8M到16M,24M,32M,48M,64M等逐步变大,但内存的变大是由于分辨率的提高导致,并不意味着可以随意声明使用内存,而不及时回收(即使Java有自己的垃圾回 ...

  6. js 相关知识整理(一)

    真正声明变量,是用逗号隔开的 EcM5:严格模式“use strict” java与js 语言的区别: 1.弱类型语言 1.声明变量时不需要提前指定数据类型 2.同一个变量可先后保存不同类型的数据 3 ...

  7. http 状态码

    一些常见的状态码为: 200 - 服务器成功返回网页 404 - 请求的网页不存在 503 - 服务不可用 详细分解: 1xx(临时响应) 表示临时响应并需要请求者继续执行操作的状态代码. 代码 说明 ...

  8. linux 技巧:使用 screen 管理你的远程会话

    你是不是经常需要 SSH 或者 telent 远程登录到 Linux 服务器?你是不是经常为一些长时间运行的任务而头疼,比如系统备份.ftp 传输等等.通常情况下我们都是为每一个这样的任务开一个远程终 ...

  9. AFNetworking 2.0指北

    AFNetworking 2.0 来了 SEP 30TH, 2013 前几天 Mattt 发布了 AFNetworking 2.0,我的一个最大感慨就是,他怎么那么高产? 关于 Mattt Mattt ...

  10. as3绕过策略文件给视频截图

    接上篇 http://www.cnblogs.com/DarkMaster/p/5973593.html 这篇同样是在老外博客上找到的,分享给大家,再次感叹老外牛逼啊. 原文地址:http://gam ...