原文:《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, ));

    }



}

OnRender方法传递了一个单独的DrawingContext类型的参数。这是一个WPF中低级别的绘图API。它提供了一组基础绘图操作,这些都在表7-4中列出。示例7-47使用了DrawRectangle和DrawText方法。

注意到DrawingContext使用了Brush和Pen类来指出形状是如何填充和画轮廓的,正如我们之前看到的高级别形状对象。我们还可以传递同样的Geometry和Drawing对象——也是在本章前面看到的。

Table 7-4. DrawingContext drawing operations

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

<?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-56





注意到,示例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.可视化层编程的更多相关文章

  1. [Real World Haskell翻译]第24章 并发和多核编程 第一部分并发编程

    第24章 并发和多核编程 第一部分并发编程 当我们写这本书的时候,CPU架构正在以比过去几十年间更快的速度变化. 并发和并行的定义 并发程序需要同时执行多个不相关任务.考虑游戏服务器的例子:它通常是由 ...

  2. 《Programming WPF》翻译 目录

    原文:<Programming WPF>翻译 目录 注:第1.2章我只做了笔记,没有翻译,请大家阅读时注意. 还有就是,这本书的英文版本下载:[O'Reilly] Programming ...

  3. 《Programming WPF》翻译 第9章 5.默认可视化

    原文:<Programming WPF>翻译 第9章 5.默认可视化 虽然为控件提供一个自定义外观的能力是有用的,开发者应该能够使用一个控件而不用必须提供自定义可视化.这个控件应该正好工作 ...

  4. 《Programming WPF》翻译 第9章 6.我们进行到哪里了?

    原文:<Programming WPF>翻译 第9章 6.我们进行到哪里了? 只有当任何内嵌控件都没有提供你需要的底层行为时,你将要写一个自定义控件.当你写一个自定义控件,你将要使用到依赖 ...

  5. 《Programming WPF》翻译 第9章 4.模板

    原文:<Programming WPF>翻译 第9章 4.模板 对一个自定义元素最后的设计考虑是,它是如何连接其可视化的.如果一个元素直接从FrameworkElement中派生,这将会适 ...

  6. 《Programming WPF》翻译 第9章 3.自定义功能

    原文:<Programming WPF>翻译 第9章 3.自定义功能 一旦你挑选好一个基类,你将要为你的控件设计一个API.大部分WPF元素提供属性暴露了多数功能,事件,命令,因为他们从框 ...

  7. 《Programming WPF》翻译 第9章 2.选择一个基类

    原文:<Programming WPF>翻译 第9章 2.选择一个基类 WPF提供了很多类,当创建一个自定义元素时,你可以从这些类中派生.图9-1显示了一组可能作为类--可能是合适的基类, ...

  8. 《Programming WPF》翻译 第9章 1.自定义控件基础

    原文:<Programming WPF>翻译 第9章 1.自定义控件基础 在写一个自定义控件之前,你需要问的第一个问题是,我真的需要一个自定义控件吗?一个写自定义控件的主要原因是为了用户界 ...

  9. 《Programming WPF》翻译 第8章 4.关键帧动画

    原文:<Programming WPF>翻译 第8章 4.关键帧动画 到目前为止,我们只看到简单的点到点的动画.我们使用了To和From属性或者By属性来设计动画--相对于当前的属性值.这 ...

随机推荐

  1. 外部函数接口 LibFFI

    “FFI” 的全名是 Foreign Function Interface,通常指的是允许以一种语言编写的代码调用另一种语言的代码.而 “Libffi” 库只提供了最底层的.与架构相关的.完整的”FF ...

  2. android 遍历所有文件夹和子目录搜索文件

    java代码: import java.io.File; import android.app.Activity; import android.os.Bundle; import android.v ...

  3. JDBC中Statement接口提供的execute、executeQuery和executeUpdate之间的区别

    Statement 接口提供了三种执行 SQL 语句的方法:executeQuery.executeUpdate 和 execute.使用哪一个方法由 SQL 语句所产生的内容决定. 方法execut ...

  4. tooltips弹出框制作

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  5. Windows下模拟Linux开发

    1.背景 Linux环境下开发是大势所趋,也是开发者必须掌握的技能.然windows系统已深入人心,实在不想放弃windows下的成熟应用,因此可以在Windows上模拟一个Linux系统.这样就满足 ...

  6. wcf简单的创建和运用

    创建一个控制台应用程序,命名为wcftest,并在同一解决方案中添加一个wcf服务应用程序 在wcf项目中会自动生成Service1.svc服务程序文件和IService1.cs契约接口 IServi ...

  7. H264编码技术

    H.264的目标应用涵盖了眼下大部分的视频服务,如有线电视远程监控.交互媒体.数字电视.视频会议.视频点播.流媒体服务等.H.264为解决不同应用中的网络传输的差异.定义了两层:视频编码层(VCL:V ...

  8. Smack+Openfire 接收和发送文件

    转载请注明出处:http://blog.csdn.net/steelychen/article/details/37958839 发送文件须要提供准确的接收放username称(例:user2@192 ...

  9. Android UI开发详解之ActionBar .

    在Android3.0之后,Google对UI导航设计上进行了一系列的改革,其中有一个非常好用的新功能就是引入的ActionBar,他用于取代3.0之前的标题栏,并提供更为丰富的导航效果. 一.添加A ...

  10. Citrix 服务器虚拟化之九 Xenserver虚拟机的XenMotion

    Citrix 服务器虚拟化之九 Xenserver虚拟机的XenMotion XenMotion 是 XenServer 的一项功能,能够将正在运行的虚拟机从一台 XenServer 主机上迁移到另外 ...