(WPF学习记录)第十章 自定义Element
2009-03-12 15:01
411 查看
在WPF中,有自定义element和自定义control的区分。自定义element,继承自FrameworkElement,如Image,Panel,TextBlock,Shape等,而自定义控件(control),是继承自Control的,或继承派生自Control的(如ContentControl)。
继承比较底层的FrameworkElement,我们可以有更多的发挥空间,而继承自Control,我们可以得到很多有用的功能,因为Control比FrameworkElement多了一些属性,如Background,Foreground等。如果只是想修改一些最常用的控件,如Button,Grid等,那就更好的,直接继承这些控件就可以了。
另外,Control类修改了一些原来的属性的默认值。FrameworkElement定义了Focusable,默认值是false,而Control继承自FrameworkElement,其Focusable的默认值是true。这意味着,Control是“可以接受键盘输入焦点”的Element。
第01个小程序:又一个椭圆
绘制椭圆的类,BetterEllipse.cs。
下面是程序入口函数代码:RenderTheBetterEllipse.cs。
运行效果截图:
第02个小程序:中世纪按钮
按钮类,MedievalButton.cs。
GetMedieval.cs。
运行效果截图:
继承比较底层的FrameworkElement,我们可以有更多的发挥空间,而继承自Control,我们可以得到很多有用的功能,因为Control比FrameworkElement多了一些属性,如Background,Foreground等。如果只是想修改一些最常用的控件,如Button,Grid等,那就更好的,直接继承这些控件就可以了。
另外,Control类修改了一些原来的属性的默认值。FrameworkElement定义了Focusable,默认值是false,而Control继承自FrameworkElement,其Focusable的默认值是true。这意味着,Control是“可以接受键盘输入焦点”的Element。
第01个小程序:又一个椭圆
绘制椭圆的类,BetterEllipse.cs。
using System; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; using System.Globalization; namespace Chapter10 { public class BetterEllipse : FrameworkElement { // 依赖项属性 public static readonly DependencyProperty FillProperty; public static readonly DependencyProperty StrokeProperty; public Brush Fill { set { SetValue(FillProperty, value); } get { return (Brush)GetValue(FillProperty); } } public Pen Stroke { set { SetValue(StrokeProperty, value); } get { return (Pen)GetValue(StrokeProperty); } } // 静态构造函数 static BetterEllipse() { FillProperty = DependencyProperty.Register("Fill", typeof(Brush), typeof(BetterEllipse), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender)); StrokeProperty = DependencyProperty.Register("Stroke", typeof(Pen), typeof(BetterEllipse), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsMeasure)); } // 重写MeasureOverride protected override Size MeasureOverride(Size sizeAvailable) { Size sizeDesired = base.MeasureOverride(sizeAvailable); if (Stroke != null) sizeDesired = new Size(Stroke.Thickness, Stroke.Thickness); return sizeDesired; } // 重写OnRender protected override void OnRender(DrawingContext dc) { Size size = RenderSize; // 调整画笔宽度 if (Stroke != null) { size.Width = Math.Max(0, size.Width - Stroke.Thickness); size.Height = Math.Max(0, size.Height - Stroke.Thickness); } // 绘制椭圆 dc.DrawEllipse(Fill, Stroke, new Point(RenderSize.Width / 2, RenderSize.Height / 2), size.Width / 2, size.Height / 2); // 下面绘制字体 FormattedText formtxt = new FormattedText("大家好,我是椭圆!", CultureInfo.CurrentCulture, FlowDirection, new Typeface("Times New Roman Italic"), 24, Brushes.DarkBlue); // 显示在椭圆中央 Point ptText = new Point((RenderSize.Width - formtxt.Width) / 2, (RenderSize.Height - formtxt.Height) / 2); dc.DrawText(formtxt, ptText); } } }
下面是程序入口函数代码:RenderTheBetterEllipse.cs。
using System; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; namespace Chapter10 { public class RenderTheBetterEllipse : Window { [STAThread] public static void Main() { Application app = new Application(); app.Run(new RenderTheBetterEllipse()); } public RenderTheBetterEllipse() { Title = "绘一个更好的椭圆"; BetterEllipse elips = new BetterEllipse(); elips.Fill = Brushes.AliceBlue; elips.Stroke = new Pen( new LinearGradientBrush( Colors.CadetBlue, Colors.Chocolate, new Point(1, 0), new Point(0, 1)),24); // 1/4英寸 Content = elips; } } }
运行效果截图:
第02个小程序:中世纪按钮
按钮类,MedievalButton.cs。
using System; using System.Globalization; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; namespace chapter10 { public class MedievalButton : Control { // 两个私有字段 FormattedText formtxt; bool isMouseReallyOver; // 静态只读字段 public static readonly DependencyProperty TextProperty; public static readonly RoutedEvent KnockEvent; public static readonly RoutedEvent PreviewKnockEvent; // 静态构造函数 static MedievalButton() { // 注册依赖项属性 TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(MedievalButton), new FrameworkPropertyMetadata( " ", FrameworkPropertyMetadataOptions.AffectsMeasure)); // 注册路由事件 KnockEvent = EventManager.RegisterRoutedEvent("Knock", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MedievalButton)); PreviewKnockEvent = EventManager.RegisterRoutedEvent("PreviewKnock", RoutingStrategy.Tunnel, typeof(RoutedEventHandler), typeof(MedievalButton)); } // 依赖项属性的公共接口 public string Text { set { SetValue(TextProperty, value == null ? " " : value); } get { return (string)GetValue(TextProperty); } } // 路由事件的公共接口 public event RoutedEventHandler Knock { add { AddHandler(KnockEvent, value); } remove { RemoveHandler(KnockEvent, value); } } public event RoutedEventHandler PreviewKnock { add { AddHandler(PreviewKnockEvent, value); } remove { RemoveHandler(PreviewKnockEvent, value); } } // 按钮尺寸改变时调用MeasureOverride protected override Size MeasureOverride(Size sizeAvailable) { formtxt = new FormattedText( Text, CultureInfo.CurrentCulture, FlowDirection, new Typeface(FontFamily, FontStyle, FontWeight, FontStretch), FontSize, Foreground); // 计算尺寸时考虑Padding Size sizeDesired = new Size(Math.Max(48, formtxt.Width) + 4, formtxt.Height + 4); sizeDesired.Width += Padding.Left + Padding.Right; sizeDesired.Height += Padding.Top + Padding.Bottom; return sizeDesired; } // 调用OnRender绘制按钮 protected override void OnRender(DrawingContext dc) { // 设定背景颜色 Brush brushBackground = Brushes.Coral; if (isMouseReallyOver && IsMouseCaptured) brushBackground = Brushes.Cyan; // 设定笔宽 Pen pen = new Pen(Foreground, IsMouseOver ? 2 : 1); // 绘制实心圆角矩形 dc.DrawRoundedRectangle(brushBackground, pen, new Rect(new Point(0, 0), RenderSize), 4, 4); // 设定前景颜色 formtxt.SetForegroundBrush( IsEnabled ? Foreground : Brushes.Red); // 设定文字起始坐标 Point ptText = new Point(2, 2); switch (HorizontalContentAlignment) { case HorizontalAlignment.Left: ptText.X += Padding.Left; break; case HorizontalAlignment.Right: ptText.X += RenderSize.Width - formtxt.Width - Padding.Right; break; case HorizontalAlignment.Center: case HorizontalAlignment.Stretch: ptText.X += (RenderSize.Width - formtxt.Width - Padding.Left - Padding.Right) / 2; break; } switch (VerticalContentAlignment) { case VerticalAlignment.Top: ptText.Y += Padding.Top; break; case VerticalAlignment.Bottom: ptText.Y += RenderSize.Height - formtxt.Height - Padding.Bottom; break; case VerticalAlignment.Center: case VerticalAlignment.Stretch: ptText.Y += (RenderSize.Height - formtxt.Height - Padding.Top - Padding.Bottom) / 2; break; } // 绘制文本 dc.DrawText(formtxt, ptText); } // 鼠标事件 影响按钮的外观 protected override void OnMouseEnter(MouseEventArgs args) { base.OnMouseEnter(args); InvalidateVisual(); } protected override void OnMouseLeave(MouseEventArgs args) { base.OnMouseLeave(args); InvalidateVisual(); } protected override void OnMouseMove(MouseEventArgs args) { base.OnMouseMove(args); // 判断鼠标是否移出按钮 Point pt = args.GetPosition(this); bool isReallyOverNow = (pt.X >= 0 && pt.X < ActualWidth && pt.Y >= 0 && pt.Y < ActualHeight); if (isReallyOverNow != isMouseReallyOver) { isMouseReallyOver = isReallyOverNow; InvalidateVisual(); } } // 'Knock'事件被触发的起始点 protected override void OnMouseLeftButtonDown(MouseButtonEventArgs args) { base.OnMouseLeftButtonDown(args); CaptureMouse(); InvalidateVisual(); args.Handled = true; } // 此事件触发'Knock'事件 protected override void OnMouseLeftButtonUp(MouseButtonEventArgs args) { base.OnMouseLeftButtonUp(args); if (IsMouseCaptured) { if (isMouseReallyOver) { OnPreviewKnock(); OnKnock(); } args.Handled = true; Mouse.Capture(null); } } // 失去了鼠标捕捉,重绘。 protected override void OnLostMouseCapture(MouseEventArgs args) { base.OnLostMouseCapture(args); InvalidateVisual(); } // OnKnock方法引发'Knock'事件 public virtual void OnKnock() { RoutedEventArgs argsEvent = new RoutedEventArgs(); argsEvent.RoutedEvent = MedievalButton.PreviewKnockEvent; argsEvent.Source = this; RaiseEvent(argsEvent); } // OnPreviewKnock方法引发'PreviewKnock'事件 public virtual void OnPreviewKnock() { RoutedEventArgs argsEvent = new RoutedEventArgs(); argsEvent.RoutedEvent = MedievalButton.KnockEvent; argsEvent.Source = this; RaiseEvent(argsEvent); } } }
GetMedieval.cs。
using System; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; namespace chapter10 { public class GetMedieval : Window { [STAThread] public static void Main() { Application app = new Application(); app.Run(new GetMedieval()); } MedievalButton btn = new MedievalButton(); public GetMedieval() { Title = "中世纪按钮"; btn.Text = "点击这个按钮"; btn.FontSize = 24; btn.HorizontalAlignment = HorizontalAlignment.Center; btn.VerticalAlignment = VerticalAlignment.Center; btn.Padding = new Thickness(15, 30, 15, 30); btn.Knock += ButtonOnKnock; Content = btn; } void ButtonOnKnock(object sender, RoutedEventArgs args) { MedievalButton btn = args.Source as MedievalButton; MessageBox.Show("按钮 /"" + btn.Text + "/" 被点击.", Title); } // 键盘的空格和回车也会触发按钮 protected override void OnKeyDown(KeyEventArgs args) { base.OnKeyDown(args); if (args.Key == Key.Space || args.Key == Key.Enter) args.Handled = true; } protected override void OnKeyUp(KeyEventArgs args) { base.OnKeyUp(args); if (args.Key == Key.Space || args.Key == Key.Enter) { btn.OnPreviewKnock(); btn.OnKnock(); args.Handled = true; } } } }
运行效果截图:
相关文章推荐
- (WPF学习记录)第十一章 单一孩子的Element
- 跟着小王学习wpf系列之十四 单个孩子的自定义element
- (WPF学习记录)第十二章 自定义面板
- WPF入门教程系列一——基础 一、 前言 最近在学习WPF,学习WPF首先上的是微软的MSDN,然后再搜索了一下网络有关WPF的学习资料。为了温故而知新把学习过程记录下来,以备后
- WPF学习笔记-用Expression Blend制作自定义按钮
- WPF学习总结和记录(六)-文本和墨水
- 流畅的python第十章序列的修改,散列和切片学习记录
- 新手学习wpf记录 等级1
- iOS学习爬坑记录8:关于自定义Cell的一点认识
- Oracle学习记录——使用自定义函数和触发器实现主键动态生成
- (WPF学习记录)第二章 基本画刷
- WPF 学习记录——Buttons and Other Controls
- WPF 学习记录——源码实例
- salesforce 零基础学习(二十三)数据记录导出至excel(自定义报表导出)
- wpf学习笔记(4)《都是自己根据网络资源学习记录的仅供参考》
- django学习记录-django-1.5中简单地自定义自己的用户模型
- WPF学习总结和记录(九)-Grid仿VS的界面
- wpf的学习记录1
- WPF学习总结和记录(四)Items控件下
- 学习记录:自定义View(仿汽车之家下拉选择页面 继承自FrameLayout)