先来看看 iPhone 的短信界面,就当是麻豆了 ^-^.
这么简洁美丽又大方的界面也就苹果想的出来.
刚看到这个界面,口水就止不住啊.
擦干口水,赶紧模仿.
最初做法:
基于 UserControl,自己做一个用户控件,内含 TextBolck 可以实现多行显示文本,
使用 Path 和 Geometry 将带有小尾巴的图形画出来,然后再画上光照效果,就大功
告成了.
虽然效果能做出来,但是细细想来,还是有不妥.
问题就在于,自己作的这个控件,只能显示文字,为了要显示图片,还得写一堆代码,
太过死板,为什么就不能利用 WPF 的框架或特点,让这个控件变的灵活一些,只要些
绘图效果和控制布局的效果就 OK 了,至于内部包含的是文字还是图片,就交给 WPF 去
完成好了.
基于此,立马想到为 TextBlock 控件写个 Template, 但稍稍一定神发现,用 Template
完成复杂图形的绘制有些虚无缥缈,结果放弃.
在老大的点化之下,采用 Decorater.乍看之下,有点摸不着北,细细看来,发现,
Border 就是从此类继承而来,说白了就是包含一个子元素的容器,自定义的 Decorater
负责绘制图形背景,显示的内容就交给子元素去完成.
为什么不用 Border 而用它,道理就是用它就足够了,干净.
(当然了,容器还有 Panel,ContentControl,在这里用 Decorater 就够了).
主要就是用到基类的方法:
MeasureOverride:通过测量子元素来计算需要的空间的大小.
ArrangeOverride:排列子元素的显示位置.
OnRender:自绘函数,带小尾巴的图形绘制就在这里了,等价于 OnPaint.
最终的效果:
实现.
自定义 IDecorator 类:
public class iDecorator: Decorator {
public iDecorator() {
this.HorizontalAlignment = System.Windows.HorizontalAlignment.Right;
}
public bool Direction {
get {
return (bool) GetValue(DirectionProperty);
}
set {
SetValue(DirectionProperty, value);
}
}
protected override Size MeasureOverride(Size constraint) {
Size result = new Size();
if (Child != null) {
Child.Measure(constraint);
result.Width = Child.DesiredSize.Width + padding.Left + padding.Right;
result.Height = Child.DesiredSize.Height + padding.Top + padding.Bottom;
if (result.Height < 35) {
result.Height = 35;
padding.Top = padding.Bottom = (result.Height - Child.DesiredSize.Height) / 2;
}
}
return result;
}
protected override Size ArrangeOverride(Size arrangeSize) {
if (Child != null) {
Child.Arrange(new Rect(new Point(padding.Left, padding.Top), Child.DesiredSize));
}
return arrangeSize;
}
protected override void OnRender(DrawingContext dc) {
if (Child != null) {
Geometry cg = null;
Brush brush = null;
Pen pen = new Pen();
pen.Brush = new SolidColorBrush(Colors.Black);
pen.Thickness = 1;
if (Direction) {
//生成小尾巴在右侧的图形和底色
cg = CreateGeometryTailAtRight();
brush = CreateBrushTailAtRight();
} else {
//生成小尾巴在左侧的图形和底色
cg = CreateGeometryTailAtLeft();
brush = CreateBrushTailAtLeft();
}
dc.DrawGeometry(brush, pen, cg);
//绘制光照效果
GradientStopCollection gscLight = new GradientStopCollection();
gscLight.Add(new GradientStop(Color.FromArgb(0xDA, 0xFF, 0xFF, 0xFF), 0));
gscLight.Add(new GradientStop(Color.FromArgb(0x68, 0xFF, 0xEF, 0xFF), 1));
Brush lightBrush = new LinearGradientBrush(gscLight, new Point(0, 0), new Point(0, 1));
dc.DrawRoundedRectangle(lightBrush, null, new Rect(22, 1, this.ActualWidth - 45, 20), 10, 10);
}
//省略部分代码...
public static void OnDirectionPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) {
var self = d as iDecorator;
self.HorizontalAlignment = (bool) e.NewValue ? HorizontalAlignment.Right: HorizontalAlignment.Left;
}
private Thickness padding = new Thickness(25, 6, 25, 6);
public static readonly DependencyProperty DirectionProperty = DependencyProperty.Register("Direction", typeof(bool), typeof(iDecorator), new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.AffectsRender, OnDirectionPropertyChangedCallback));
}
调用处:
短信框的小尾巴在右侧:
<local:iDecorator HorizontalAlignment="Right" Direction="True">
<TextBlock MaxWidth="200" Foreground="Black" TextWrapping="Wrap">
前两天去哪儿了,听说去北京了???
</TextBlock>
</local:iDecorator>
短信框的小尾巴在左侧:
就是把 Direction(方向)设成 False 即可.
<local:iDecorator HorizontalAlignment="Right" Direction="False">
<TextBlock MaxWidth="200" Foreground="Black" TextWrapping="Wrap">
前两天去哪儿了,听说去北京了???
</TextBlock>
</local:iDecorator>
调用是不是很方便,把它当成容器用就行了.
大功告成!
代码:http://download.csdn.net/download/kongxh_1981/9161495
来源: http://lib.csdn.net/article/csharp/35968