您的位置:首页 > 其它

(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。

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;
}
}
}
}


运行效果截图:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: