在实际工作中,面对不同的客户需求,需要让空间显示出不同的效果。当style已经不能足够满足客户需求时,就需要程序猿自己设计自定义控件了。

根据工作经历,LZ做了个关于自定义控件的小Demo,仅供参考。

实现操作分为三部分,话不多说,直接上代码。

一.控件后台设置

public class ImageButton : Button
{
public ImageButton() {
this.PreviewMouseDown += ImageButton_PreviewMouseDown;
this.PreviewMouseUp += ImageButton_PreviewMouseUp;
} void ImageButton_PreviewMouseUp(object sender, MouseButtonEventArgs e)
{
MessageBox.Show("");
} void ImageButton_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
MessageBox.Show(""); } public ImageSource ImageSource
{
get { return (ImageSource)GetValue(ImageSourceProperty); }
set { SetValue(ImageSourceProperty, value); }
} public static readonly DependencyProperty ImageSourceProperty =
DependencyProperty.Register("ImageSource", typeof(ImageSource), typeof(ImageButton), new UIPropertyMetadata(null));
}

根据控件需求对这个类做不同的继承,LZ做的控件是Button,所以继承自Button。
然后对ImageSource对应下文的Binding,做依赖属性。

this.PreviewMouseDown+=PreviewMouseDown;是对Button本身的响应事件做绑定。

二.控件界面设定

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:helper="clr-namespace:DemoZDY">
<Style TargetType="{x:Type helper:ImageButton}">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Cursor" Value="Hand" />
<Setter Property="FontFamily" Value="微软雅黑" />
<Setter Property="FontSize" Value=""/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type helper:ImageButton}">
<StackPanel>
<Image Name="Image" Stretch="Fill" Source="{TemplateBinding ImageSource}" />
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

控件内容比较简单,上面一个图片,下面一个Text内容。

Helper是指(一)中的命名空间。

三.MainWindow界面

<Window x:Class="DemoZDY.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="" Width=""
xmlns:helper="clr-namespace:DemoZDY">
<StackPanel>
<helper:ImageButton ImageSource="Status-False.png" Width="" Content="Click"/>
</StackPanel>
</Window>

简单一个自定义控件完成。但该控件不是很具体,下面再写一个稍微复杂点的自定义Buton控件。

四.新自定义button

  控件界面差别不大,主要是后台代码和使用的图片资源不同。

  (1)图片

点击效果:正常状态下显示上半部分,在被点击时显示下半部分,点击后恢复上半部分。

  (2)控件后台代码

 [TemplatePart(Name = "PART_Image", Type = typeof(Image))]
public class HoverButton : Button
{
private void OnImageSourceChanged(ImageSource oldValue, ImageSource newValue)
{
if (newValue is BitmapSource)
{
int w = (int)(newValue.Width);
int h = (int)(newValue.Height / ); NormalImage = new CroppedBitmap(newValue as BitmapSource, new Int32Rect(, , w, h));
PressedImage = new CroppedBitmap(newValue as BitmapSource, new Int32Rect(, h, w, h));
}
} public HoverButton()
{
this.PreviewMouseDown += OnPreviewMouseDown;
this.PreviewMouseUp += OnPreviewMouseUp;
} private void OnPreviewMouseDown(object sender, MouseButtonEventArgs e)
{
if (image != null)
{
image.Source = PressedImage;
this.CaptureMouse();
}
//e.Handled = true;
} private void OnPreviewMouseUp(object sender, MouseButtonEventArgs e)
{
if (image != null)
{
if (this.IsMouseCaptured)
{
this.ReleaseMouseCapture();
} image.Source = NormalImage;
this.OnClick();
}
//e.Handled = true;
} public override void OnApplyTemplate()
{
base.OnApplyTemplate();
image = this.GetTemplateChild("PART_Image") as Image;
} public ImageSource ImageSource
{
get { return (ImageSource)GetValue(ImageSourceProperty); }
set { SetValue(ImageSourceProperty, value); }
} public ImageSource NormalImage
{
get { return (ImageSource)GetValue(NormalImageProperty); }
set { SetValue(NormalImageProperty, value); }
} public ImageSource PressedImage
{
get { return (ImageSource)GetValue(PressedImageProperty); }
set { SetValue(PressedImageProperty, value); }
} public static void OnImageSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as HoverButton).OnImageSourceChanged(e.OldValue as ImageSource, e.NewValue as ImageSource);
} static HoverButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(HoverButton), new FrameworkPropertyMetadata(typeof(HoverButton)));
} public static readonly DependencyProperty ImageSourceProperty =
DependencyProperty.Register("ImageSource", typeof(ImageSource), typeof(HoverButton), new UIPropertyMetadata(null, OnImageSourceChanged)); public static readonly DependencyProperty NormalImageProperty =
DependencyProperty.Register("NormalImage", typeof(ImageSource), typeof(HoverButton), new UIPropertyMetadata(null)); public static readonly DependencyProperty PressedImageProperty =
DependencyProperty.Register("PressedImage", typeof(ImageSource), typeof(HoverButton), new UIPropertyMetadata(null)); public Image image;
}
  • [TemplatePart(Name = "PART_Image", Type = typeof(Image))],是一种契约,意思是告诉要来写ControlTemplate的用户 , 你的ControlTemplate中需要有一个x:Name为“PART_Image” , 类型为Image, 当然这个类型可以是继承来的, 为什么一定要包含这些契约规定的元素 , 因为逻辑部分对这些东西进行了引用,它们将对控件的默认行为起着关键作用, 可以理解为这个控件的最基本元素 , 是实现默认行为的最小集合, 自然,你的ControlTemplate中如果没有包含契约中的内容 , 则相应的逻辑将无法实现。
  • OnImageSourceChanged里意思是将图片分为上下两部分(NormalImage和PressedImage)
  • CaptureMouse和ReleaseMouseCapture是指光标的捕获和释放。
  • OnApplyTemplate 显示由自定义控件定义的 OnApplyTemplate 重写,设计该自定义控件是因为考虑到调用方可能通过模板和样式系统来定义和应用自己的控件模板。  作为其定义的一部分,模板中命名元素的控件属性是必需的,如 UpButtonElement。  然后 OnApplyTemplate 在加载模板时基于此命名协定检索对象引用。  此外,此示例还调用专用方法 UpdateState(未显示定义)。  这是 OnApplyTemplate 的另一个常见方案:确保为控件的起始状态设置可视状态,在此例中,通过调用专用方法来确保,该专用方法考虑了控件的所有已定义状态并调用 GoToState 来设置适当的状态。 (msdn.microsoft.com中的定义)
  • 其他的都很简单,切记要依赖属性。

五.Demo下载

WPF 自定义控件的更多相关文章

  1. WPF自定义控件与样式(3)-TextBox & RichTextBox & PasswordBox样式、水印、Label标签、功能扩展

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

  2. WPF自定义控件与样式(1)-矢量字体图标(iconfont)

    一.图标字体 图标字体在网页开发上运用非常广泛,具体可以网络搜索了解,网页上的运用有很多例子,如Bootstrap.但在C/S程序中使用还不多,字体图标其实就是把矢量图形打包到字体文件里,就像使用一般 ...

  3. WPF自定义控件与样式(2)-自定义按钮FButton

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

  4. WPF自定义控件与样式(15)-终结篇 & 系列文章索引 & 源码共享

    系列文章目录  WPF自定义控件与样式(1)-矢量字体图标(iconfont) WPF自定义控件与样式(2)-自定义按钮FButton WPF自定义控件与样式(3)-TextBox & Ric ...

  5. WPF自定义控件与样式(4)-CheckBox/RadioButton自定义样式

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

  6. WPF自定义控件与样式(5)-Calendar/DatePicker日期控件自定义样式及扩展

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

  7. WPF自定义控件与样式(6)-ScrollViewer与ListBox自定义样式

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

  8. WPF自定义控件与样式(7)-列表控件DataGrid与ListView自定义样式

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

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

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

  10. WPF自定义控件与样式(9)-树控件TreeView与菜单Menu-ContextMenu

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

随机推荐

  1. phalcon:跟踪sql语句

    在phalcon里有一个\Phalcon\Db\Profiler 类,这个类可以用来记录sql语句并计算消耗的时间.那么如何使用它呢? 手册里其实已经提供了方法,总结如下: 1.向$di里注册prof ...

  2. [转]LUA元表

    lua元表和元方法 <lua程序设计> 13章 读书笔记 lua中每个值都有一个元表,talble和userdata可以有各自独立的元表,而其它类型的值则共享其类型所属的单一元表.lua在 ...

  3. Scalding初探之一:基于Scala的Hadoop利器

    把你从写繁琐的Map-reduce Job中解放出来,写分布式跟写本地程序没两样,Scala真真代表着先进生产力的方向啊. 好的,今天开始直播基于Scala的Scalding啦,循序渐进地看以下页面: ...

  4. C++中的初始化

    C++中的RAII机制指明”对象创建时通过构造函数进行初始化,析构时通过析构函数释放资源”,但实际中因类无构造函数时编译器将自动合成一个默认构造函数,该构造函数只服务于自身编译器构造需要而不负责对象成 ...

  5. 连HTTPS都有漏洞,这么不安全的互联网我们还要继续用吗?

    转载自 http://www.huxiu.com/article/45302/1.html 10月24日和25日,虎嗅君参加了GeekPwn(极棒)安全极客嘉年华活动.   嗯...说是嘉年华,其实就 ...

  6. C++实现不能被继承的类——终结类 分类: C/C++ 2015-04-06 14:48 64人阅读 评论(0) 收藏

    1.       问题 C++如何实现不能被继承的类,即终结类.Java中有final关键字修饰,C#中有sealed关键字修饰,而C++目前还没有类似的关键字来修饰类实现终结类,需编程人员手动实现. ...

  7. 编译llvm+clang

    第一步,下载llvm代码: git clone git@github.com:llvm-mirror/llvm.git 第二步,进入llvm/tools目录并下载clang代码 cd llvm/too ...

  8. ubnt+ros 接入无线

    ubnt+ros 接入无线 一.ubnt配置(UBNT NanoStation LOCOM2 LOCO M2)1.ubnt接poe,转lan接到pc2.ubnt默认ip是192.168.1.20,用户 ...

  9. loose coupling之函数签名

    当函数的参数有多个时(比如多于4个),可以考虑将这些参数组织放入一个class(struct),然后函数参数就减少为一个. 1.以class instance来穿参数,可以很容易在各个函数之间传递参数 ...

  10. [Mongodb]3.2版本的一些基本操作--待续

    一.缘由 今天公司测试股票交易系统,需要拉取大量的数据存放,故考虑放在mongodb里. 二.一些基本操作 1.权限管理 mongo默认是不用账号就能登陆的,默认端口27017,但是这不太安全.我们要 ...