《Programming WPF》翻译 第7章 5.可视化层编程
原文:《Programming WPF》翻译 第7章 5.可视化层编程
形状元素能提供一种便利的方式与图形一起工作,在一些情形中,添加表示绘图的元素到UI树中,可能是比它的价值更加麻烦。你的数据可能被构造以一种易于编写代码的方式——简单地表现一系列基于数据的绘图操作,而不是构造一棵对象树。
WPF提供一个“可视化层”API,作为一个对形状元素较低级别的折中。(实际上,形状元素全都在可视化层得顶部被实现。)这个API使我们编写按需生成的代码。
可视化是一个可见的对象。WPF应用程序的外观是将它所有的可视化组合到屏幕上形成的。由于WPF生成在在可视化层的顶级,每个元素都是可视化的。FrameworkElement基类间接派生于Visual。在可视化层编程,简单地解决了创建一个可视化和编写代码告诉WPF我们想要在可视化中显示什么。
即使在这个低的级别,WPF的表现非常不同于Win32。图形加速的方式是托管的,这意味着你的按需生成的代码很少被调用——少于在经典Windows应用程序中。
7.5.1 按需生成
按需生成的关键定制为OnRender方法。这个方法被WPF调用在它需要你的组件生成它的外观时。(这是内嵌形状的类生成它们自身的方式。)
OnRender虚方法定义在OnDemandVisual类。大多数元素都间接的通过FrameworkElement派生于此,这就增加了核心样式如外观和输入处理。
示例7-47显示了一个字定义的元素,覆写了OnRender。
示例7-47
public class CustomRender : FrameworkElement


{
protected override void OnRender(DrawingContext drawingContext)

{
Debug.WriteLine("OnRender");

base.OnRender(drawingContext);

drawingContext.DrawRectangle(Brushes.Red, ));

FormattedText text = new FormattedText("Hello, world",
CultureInfo.CurrentUICulture, FlowDirection.LeftToRightThenTopToBottom,
, Brushes.Black);
drawingContext.DrawText(text, ));
}

}
注意到DrawingContext使用了Brush和Pen类来指出形状是如何填充和画轮廓的,正如我们之前看到的高级别形状对象。我们还可以传递同样的Geometry和Drawing对象——也是在本章前面看到的。
|
Operation |
Usage |
|---|---|
|
DrawDrawing |
Draws a Drawing object. |
|
DrawEllipse |
Draws an ellipse. |
|
DrawGeometry |
Draws any Geometry object. |
|
DrawGlyphRun |
Draws a series of glyphs (i.e., text elements) offering detailed control over typography. |
|
DrawImage |
Draws a bitmap image. |
|
DrawLine |
Draws a line (a single segment). |
|
DrawRectangle |
Draws a rectangle. |
|
DrawRoundedRectangle |
Draws a rectangle with rounded corners. |
|
DrawText |
Draws text. |
|
DrawVideo |
Draws a rectangular region that can display video. |
|
PushTransform |
Sets a transform that will be applied to all subsequent drawing operations until Pop is called; if a transform is already in place, the net effect will be the combination of all the transforms currently pushed. |
|
PushClip |
Sets a clip region that will be applied to all subsequent drawing operations until Pop is called; as with PushTransform, multiple active clip regions will combine. |
|
PushOpacity |
Sets a level of opacity that will be applied to all subsequent drawing operations until Pop is called; as with transforms and clips, multiple opacities are combined. |
|
Pop |
Removes the transform, clip region, or opacity added most recently by PushTransform, PushClip, or PushOpacity. If those methods have been called multiple times, calls to Pop remove their effects in reverse order. (The transforms, clip regions, and opacities behave like a stack.) |
因为我们的自定义元素派生于FrameworkElement,它自然地集成到任何WPF应用程序中。示例7-48为一个窗体的标记,其中包含了自定义元素,我们可以使用它就像我们之前使用的任何自定义元素。这个窗体如图7-56所示。
示例7-48
图7-56
<?Mapping XmlNamespace="controls" ClrNamespace="VisualRender" ?>
<Window x:Class="VisualRender.Window1"
xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005"
xmlns:cc="controls"
Text="Visual Layer Rendering"
>
<Canvas>
" x:Name="customRender" />
</Canvas>
</Window>

注意到,示例7-47中的OnRender方法调用了Debug.WriteLine。如果程序运行在VS2008调试器的内部,这将在每次调用OnRender方法的时候,打印出一条消息到“输出”窗体。这支持我们看到WPF如何经常要求我们的自定义可视化来生成它自身。如果你习惯于如何在在标准Win32和Windows Forms中的按需绘制下工作,你可能希望看到这被规则地调用——无论窗体重新调整大小还是部分模糊或隐藏。实际上,它只会被调用一次。
结果是按需生成并不相似于Win32的旧有样式生成,正如你可能想到的。WPF会调用你的OnRender方法当它需要知道你的可视化显示什么内容,但是图形加速的工作方式意味着这种情况的发生远远少于Win32中等价的重画。WPF缓存了生成指令。这种缓存的范围和形式并没有文本化,但是它清晰的发生了。进一步而言,这比简单的基于图像的缓存要微妙的多。我们可以添加这些代码到示例7-48的宿主窗体(在后台代码文件中可能是这样的)。
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
VisualOperations.SetTransform(CustomRender, ));
}先前的片断应用了转换到我们的元素,以因数6放大。当点击用户界面时,自定义可视化会如你想希望的方式延伸,而且OnRender并没有被调用。不仅如此,放大的可视化并没有显示任何你可以看到的像素化或模糊化的人造物,通过一个简单的图像缩放。它继续是锐利的,正如你在图7-57看到的。
图7-57

这指出了WPF获取关于可视化内容的缩放信息。它能重绘我们的可视化的屏幕外观,而不使用我们的OnRender方法,即使当转换有所改变。这在局部上取决于加速构架,而且同样因为转换支持在大多数基础的级别生成在WPF中。
WPF重绘的能力——不使用OnRender,允许用户界面在屏幕上保持完整,即使我们的应用程序很繁忙。它同样支持动画系统工作而不用很多来自应用程序的干扰,因为所有的基础绘制操作都被保留了,WPF可以重建任何部分的UI——当独立的元素改变的时候。
如果我们对象的状态必须在某种程度上改变——需要更新外观,我们可以调用InvalidateVisual方法。这将导致WPF调用我们的OnRender方法,允许我们重建外观。
注意到,当你重写OnRender的时候,你还应该典型地覆写MeasureOverrid和ArrangeOverride方法。否则,WPF的外观系统不会知道你的元素有多大。我们得到的唯一原因,而不用在这里这么做,是我们在Canvas上使用该元素,这将不会关心它的子元素有多大。为了在其它的面板上工作,这是实质的让外观系统知道你的大小。第二章描述了MeasureOverrid和ArrangeOverride方法。
《Programming WPF》翻译 第7章 5.可视化层编程的更多相关文章
- [Real World Haskell翻译]第24章 并发和多核编程 第一部分并发编程
第24章 并发和多核编程 第一部分并发编程 当我们写这本书的时候,CPU架构正在以比过去几十年间更快的速度变化. 并发和并行的定义 并发程序需要同时执行多个不相关任务.考虑游戏服务器的例子:它通常是由 ...
- 《Programming WPF》翻译 目录
原文:<Programming WPF>翻译 目录 注:第1.2章我只做了笔记,没有翻译,请大家阅读时注意. 还有就是,这本书的英文版本下载:[O'Reilly] Programming ...
- 《Programming WPF》翻译 第9章 5.默认可视化
原文:<Programming WPF>翻译 第9章 5.默认可视化 虽然为控件提供一个自定义外观的能力是有用的,开发者应该能够使用一个控件而不用必须提供自定义可视化.这个控件应该正好工作 ...
- 《Programming WPF》翻译 第9章 6.我们进行到哪里了?
原文:<Programming WPF>翻译 第9章 6.我们进行到哪里了? 只有当任何内嵌控件都没有提供你需要的底层行为时,你将要写一个自定义控件.当你写一个自定义控件,你将要使用到依赖 ...
- 《Programming WPF》翻译 第9章 4.模板
原文:<Programming WPF>翻译 第9章 4.模板 对一个自定义元素最后的设计考虑是,它是如何连接其可视化的.如果一个元素直接从FrameworkElement中派生,这将会适 ...
- 《Programming WPF》翻译 第9章 3.自定义功能
原文:<Programming WPF>翻译 第9章 3.自定义功能 一旦你挑选好一个基类,你将要为你的控件设计一个API.大部分WPF元素提供属性暴露了多数功能,事件,命令,因为他们从框 ...
- 《Programming WPF》翻译 第9章 2.选择一个基类
原文:<Programming WPF>翻译 第9章 2.选择一个基类 WPF提供了很多类,当创建一个自定义元素时,你可以从这些类中派生.图9-1显示了一组可能作为类--可能是合适的基类, ...
- 《Programming WPF》翻译 第9章 1.自定义控件基础
原文:<Programming WPF>翻译 第9章 1.自定义控件基础 在写一个自定义控件之前,你需要问的第一个问题是,我真的需要一个自定义控件吗?一个写自定义控件的主要原因是为了用户界 ...
- 《Programming WPF》翻译 第8章 4.关键帧动画
原文:<Programming WPF>翻译 第8章 4.关键帧动画 到目前为止,我们只看到简单的点到点的动画.我们使用了To和From属性或者By属性来设计动画--相对于当前的属性值.这 ...
随机推荐
- VS2010编译Qt程序失败------error LNK1123: 转换到 COFF 期间失败:
error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏使用VS2010编译VC++项目的时候可能会出这个问题. 据说升级到SP1后可能问题解决,但是下载量太大,目前没有得到证实. ...
- JPA中以HibernatePersistence为provider的批量插入问题
为什么要批量插入 要插入10000条数据,如果不批量插入的话,那么我们执行的sql语句将是10000条insert insert into member (group_id, user_id, rol ...
- BZOJ1628: [Usaco2007 Demo]City skyline
1628: [Usaco2007 Demo]City skyline Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 256 Solved: 210[Su ...
- pthread_mutex_init & 互斥锁pthread_mutex_t的使用
pthread_mutex_init l 头文件: #include <pthread.h> l 函数原型: int pthread_mutex_init( ...
- Temporary failure in name resolution
公司搬家,在一台测试机上执行git clone,出现错误 ssh: Could not resolve hostname **: Temporary failure in name resolutio ...
- 解决Jenkins上git出现Timeout的问题
Jenkins上现有的git插件并没有配置超时的选项,因此在clone项目时如果网络差会出现“ERROR: Timeout after 10 minutes”,导致无法继续构建. 网上找到一个解决方法 ...
- opencv视频跟踪2
在前面的报告中我们实现了用SURF算法计算目标在移动摄像机拍摄到的视频中的位置.由于摄像机本身像素的限制,加之算法处理时间会随着图像质量的提高而提高,实际实验发现在背景复杂的情况下,结果偏差可能会很大 ...
- thinkphp连接mysql5.5版本数据库
//数据库配置信息 'DB_TYPE' => 'mysqli', // 数据库类型 'DB_HOST' => 'localhost', // 服务器地址 'DB_NAME' => ' ...
- char图表
首先看一下chart图表相应的各个属性: 要想使用chart图表,首先须要安装MSChart.exe:安装完后,工具箱里仍然没有,此时要在web.Config文件中加入以下代码: <span s ...
- C++设计模式---Strategy模式
一.前言 学习的第一个设计模式!不知道理解的对不对,期望大家一起多交流~ Strategy模式:策略模式,定义了算法族,分别封装起来,此模式可以让算法的变化独立于使用算法的客户.Strategy模式将 ...