65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 Microsoft Longhorn 的 XAML 和 C# 中的方块状树状图

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.38/5 (83投票s)

2004 年 5 月 14 日

42分钟阅读

viewsIcon

450158

downloadIcon

6712

使用矩形树状图进行数据可视化。

Demo application - treemaps.png

引言

在听完这个奇怪的标题后,我最好先解释一下这篇文章的内容。

我最喜欢的“宠物”话题之一是数据可视化,以及如何通过图形化显示数据来发现趋势、模式和异常,并通常改善“用户体验 (UX)”。

本文将分为三个主要部分;首先,我将讨论什么是树状图,它们如何帮助您解释数据以及它们是如何构建的。简而言之,它们提供信息的图形表示,使用户能够通过大小和变化的属性来比较项目,通常用于查看分层数据。

其次,稍微偏离主题,我将讨论为什么我希望并认为 Longhorn 和 XAML 将为桌面计算带来重要的变化。

然后回到树状图,展示如何使用 Microsoft Longhorn(Microsoft Windows 下一个版本的代号)和 Whidbey(将于明年作为 Visual Studio 2005 发布)的 alpha 版本,以及 2003 年 10 月微软专业开发者大会 (PDC) 的版本,在 C# 和 XAML 中创建树状图应用程序。

因为我知道大多数人不会安装 PDC 版本,所以我也制作了一个小视频演示,供人们以 Longhorn 概念视频的风格下载。希望微软和 Carter Maslan 会欣赏我想要宣传的热情,而不是对类似的风格感到不悦。

请注意,该视频绝非 Microsoft 制作或认可,本文中使用的代号属于其各自所有者。

Download video demo - 3762 Kb

最后,我将介绍一些我最近看到的其他可视化/交互技术,这些技术可能会让您非常感兴趣;包括商业软件包和信息查看理念。

背景

大约四年前,我在 SmartMoney 网站上偶然发现了名为树状图的图形技术。该技术在那里被用作比较金融股票信息的方式,并被称为 '市场地图'。它让我印象深刻,因为它让用户能够轻松比较多个行业和公司的不同属性的大小和变化。

为了了解它们如何计算和布局不同的区域,我深入研究并找到了关于人机交互 (HCI) 的学术论文,特别是树状图。在那里,我发现了马里兰大学的 Ben Shneiderman 所做的工作。

具体来说,埃因霍温科技大学数学与计算机科学系的 Mark Bruls、Kees Huizing 和 Jarke J. van Wijk 的论文“矩形树状图”就是我这里将使用的布局技术。

有许多使用树状图的例子,包括微软研究部门在 Netscan 上分析 Usenet 帖子,显示哪些组的帖子最多以及与上个月的变化。您可以下载他们的 Treemap.NET SDK

HiveGroup 有一款使用树状图进行商业智能数据挖掘的产品。

矩形树状图

这是一种树状图,但布局算法旨在以“最佳”纵横比绘制数据,即尝试通过接近值 1 的低纵横比来保持区域的形状“方形”。

那么让我们从一个简单的例子开始,想象我们有五家不同的公司。我们有数百万英镑的销售数据和与去年相比的百分比变化。

我们可以将数据显示为表格

或以图表形式图形化显示

这使我们能够很容易地看到公司 B(销售额最大)去年的销售额百分比变化为负。公司 F 大约是公司 E 的一半,销售额最小的是公司 G,但公司 H 的销售额百分比变化最高。

将这些信息绘制成矩形树状图,我们得到这样的图表

为了解释我们正在看什么,我们已经在网格中绘制了所有公司,大小由销售额决定;颜色表示百分比变化。希望您会同意,通过快速浏览,很容易对公司有一个很好的了解,并比较销售额的大小。此外,公司 H 上的亮绿色使其突出显示为正百分比变化,并且公司 C、D、J 和 G 的销售额大小相似。

 

这种技术对于小型数据集来说并不是那么令人印象深刻,但对于更多的公司,您可以快速浏览并找出异常。如果我们查看 Smartmoney 行业地图的几个屏幕截图,我们可以很容易地在下方看到“技术硬件和设备”和“通信技术”中的负面变化。

深入研究 Smartmoney 的软件行业,我们可以看到微软的主导地位(在市值方面)。

你真的知道微软(在市值方面)比 Oracle 大那么多吗?

布局如何工作?

现在我们已经了解了这种技术如何显示数据,我们如何决定数据的实际布局?

正如上面列出的论文“矩形树状图”中讨论的,它使用了一种布局技术来尝试获得最佳纵横比;如前所述,这意味着尝试布局元素以使比率接近值 1。

我将再次使用他们的例子,假设我们有一个 6 x 4 的区域,并且我们有七个数据项,大小分别为 6、6、4、3、2、2 1

我们可以垂直分割区域

或水平分割

两者看起来都不是很好,矩形树状图论文中提出的想法是尝试以不同的方式放置项目,以实现最佳纵横比。

 

步骤 1 :首先决定,因为我们要填充的区域比高度宽,所以我们将垂直绘制第一个元素。

bool DrawVertically (single width, single height) { 
    return width > height; 
} 

我们计算纵横比为

single aspect = Math.Max( width / height, height / width); 

我们放置一个大小为 6 的元素,给定高度为 4(因为我们垂直绘制)。

那么宽度 = 4 * ? = 6,所以 ? = 6/4 = 1.5

纵横比是 Max( 4/1.5, 1.5/4)
= 2.66

 

步骤 2 :继续垂直绘制,因为我们没有先前的纵横比可以更好。现在我们要绘制大小为 6 和 6 的前两个元素。

放置总大小为 12 (6+6),给定高度为 4 意味着

宽度 = 4 * ? = 12,所以 ? = 12/4 = 3

纵横比是 Max( 2/3, 3/2) = 1.5

它比以前的值更好,所以我们继续。

 

 

步骤 3 :再次继续垂直绘制,因为纵横比有所改善,即更接近 1。绘制列表中大小为 6、6 和 4 的前三个元素。

放置总大小为 16 (6+6+4),给定高度为 4 意味着

宽度 = 4 * ? = 16,所以 ? = 16/4 = 4

项目 1、2 的大小为 6 = 4 * 1.5
项目 3 的大小为 4 = 4 * 1

纵横比是 Max( 4/1, 1/4) = 4

更差,所以不要使用这个布局步骤。

 

 

步骤 4 :因为纵横比更差(高于步骤 2 的值并偏离值 1),我们回溯到步骤 2 并锁定该布局。

现在我们尝试将剩余的元素布局到剩余的区域中,一个 3 x 4 的空间。由于我们重新开始,检查我们是否将垂直绘制,答案是否定的,因为该区域比宽度高。让我们尝试再次放置大小为 4 的元素。

放置大小为 4 的元素,给定宽度为 3(因为现在水平绘制)意味着

高度 = 3 * ? = 4,所以 ? = 4/3 = 1.333

纵横比是 Max( 3/1.333, 1.333/3) = 2.251

新区域中的第一个项目,所以我们继续。

 

 

步骤 5 :继续,水平绘制,大小为 4 和 3 的元素。

放置总大小为 7 (4+3),给定宽度为 3 意味着

高度 = 3 * ? = 7,所以 ? = 7/3 = 2.333

项目 3 的大小为 4 = ? * 2.333 = 1.715 宽度
项目 4 的大小为 3 = ? * 2.333 = 1.289 宽度

纵横比是 Max( 2.333/1.289, 1.289/2.333) = 1.80993

比以前的值更好(更接近 1),所以我们继续。

 

步骤 6 :继续水平绘制,大小为 4、3 和 2 的元素。

放置总大小为 9,给定宽度为 3 意味着

高度 = 3 * ? = 9,所以 ? = 9/3 = 3

项目 3 的大小为 4 = ? * 3 = 1.333 宽度
项目 4 的大小为 3 = ? * 3 = 1 宽度
项目 5 的大小为 2 = ? * 3 = 0.667 宽度

纵横比是 Max ( 3/0.667, 0.667/3) = 4.498

更差,所以我们不使用这个布局步骤。

 

步骤 7 :因为纵横比更差(高于步骤 5 的值并偏离值 1),我们回溯到步骤 5 并锁定该布局。

现在我们尝试将剩余的元素布局到剩余的区域中,一个 3 x 1.67 的空间。由于我们重新开始,检查我们是否将垂直绘制,这次答案是肯定的,因为该区域比高度宽。让我们尝试再次放置大小为 2 的元素。

放置大小为 2 的元素,给定高度为 1.67(因为现在再次垂直绘制)意味着

宽度 = 1.67 * ? = 2,所以 ? = 2/1.67 = 1.198

纵横比是 Max( 1.67/1.198, 1.198/1.67) = 1.394

新区域中的第一个项目,所以我们继续。

 

步骤 8 :继续垂直绘制,大小为 2 和 2 的元素。

放置总大小为 4,给定高度为 1.67 意味着

宽度 = 1.67 * ? = 4,所以 ? = 4/1.67 = 2.4

项目 5、6 的大小为 2 = ? * 1.67 = 每个 0.84 高度

纵横比是 Max ( 0.84/2.4, 2.4/0.84) = 2.87

更差,所以我们不使用这个布局步骤。

 

步骤 9 :因为纵横比更差(高于步骤 7 的值并偏离值 1),我们回溯到步骤 7 并锁定该布局。

现在我们尝试将剩余的元素布局到剩余的区域中,一个 1.8 x 1.67 的空间。由于我们重新开始,检查我们是否将垂直绘制,这次答案又是肯定的,因为该区域比高度宽。让我们尝试再次放置大小为 2 的元素。

放置大小为 2 的元素,给定高度为 1.67(因为垂直绘制)意味着

宽度 = 1.67 * ? = 2,所以 ? = 2/1.67 = 1.198

纵横比是 Max( 1.67/1.198, 1.198/1.67) = 1.394

新区域中的第一个项目,所以我们继续。

 

步骤 10 :继续垂直绘制,大小为 2 和 1 的元素。

放置总大小为 3,给定高度为 1.67 意味着

宽度 = 1.67 * ? = 3,所以 ? = 1.8

项目 6 的大小为 2 = ? * 0.56 = 1.2 宽度
项目 7 的大小为 1 = ? * 0.56 = 0.6 宽度

作为最后一个元素,我们完成了。

 

显然,这个例子更容易理解,因为元素的总大小(6+6+4+3+2+2+1 = 24)也是总面积(6 x 4 = 24)。但是,不同数量和总大小的元素也可以放置,只需适当地缩放大小即可。

我希望大家能够理解这个解释,并且可以看到我们是如何递归地尝试不同的布局,最终结果是一组更加“方形”且布局更好的元素,大小递减。

我们将在本文稍后回到实际代码和颜色变化参数。

 

如果您只对矩形树状图代码感兴趣,请随时跳过下一部分关于 Longhorn 的讨论。


为什么 Longhorn 会带来巨大的变化?

Windows XP 之后的下一个 Microsoft Windows 版本代号为 Longhorn。微软已经发布了大量信息,包括谈论三大支柱,即 Avalon、WinFS、Indigo 和整体基础;统称为 WinFX。

我将让您阅读 Microsoft Developer Network (MSDN) 上 Longhorn Developer Center 的文章以了解更多信息。

Brent Rector 撰写的书籍 《开发者 Longhorn 简介》是一份很好的路线图指南,现在也可以在线阅读。

看看图形子系统,特别是“Avalon”,它被描述为“为在 Longhorn 中构建应用程序和高保真体验提供基础,融合应用程序 UI、文档和媒体内容,同时充分利用您的计算机的强大功能 ”。

在其之上构建的是“Aero”,它是“新的 Windows 用户体验。Aero 包括准则、建议和用户体验价值,可帮助您的应用程序充分利用 Microsoft Windows ”。您不需要完全理解这些术语,但它可能会让事情更清楚一些。

我主要关注 Avalon,并在本文中稍微提及 Aero,因为它们是 Longhorn UX 的核心。

Longhorn 中定义 UI 布局的新方法是 XAML(发音为“Zamal”)。这种新的标记语言允许您声明性地指定一组具有属性和逻辑的对象层次结构。通常这将是应用程序的用户界面 (UI),这也是我将用于下面讨论的树状图应用程序的内容。

为什么 Avalon 可能如此重要

好了,够了,这些新用户界面会是什么样子。嗯,David Massy 写了一篇博客文章,我想引用一下

“为什么选择 Longhorn 和 Avalon?”

我不知道是否还有其他人看 CSI 和 CSI: Miami 电视节目(大概有人看,否则他们就不会继续制作这个节目),这些节目讲述的是犯罪现场调查员筛选证据以找到对犯罪负责的坏人。这可能不是最好的电视节目,但我和我的未婚妻经常喜欢看它,试图猜测谁是坏人。然而,让我烦恼的是这个节目(以及许多其他电视节目和电影)展示计算机工作的方式,这些节目中的计算机拥有时尚的界面,可以立即显示查询结果,包括驾驶执照图像和其他相关数据,它们提供轮胎花纹匹配、鞋印匹配、DNA 匹配等三维分析,甚至登录屏幕也光滑且诱人。

所以在 Longhorn 中,Avalon 中的技术将使我们在这些节目中看到的各种用户界面触手可及的开发者。太棒了!

当然,你们中的那些愤世嫉俗的人可能会说“但我实际上并不真的想要看起来像电视上显示的那样”嗯,我可能会同意你的观点,因为电视节目总是会显示一些比现实世界中可能使用的更简单一些的东西,仅仅是为了让观众能够轻松地跟随情节。这并不是说电视上通常看到的一些元素没有用,也不是我们应该在下一代计算机解决方案中提供的东西。对于今天许多人来说,计算机仍然太难使用,而提供无故障的用户体验,通过动画帮助显示任务流程来引导您完成任务,我相信会有所帮助。”


《Discover》杂志最近的一篇文章文章,谈到了“我的图片”未来可能如何工作,“如果你连续拍摄 10 张日落照片,软件会识别出所有这些照片都是在几分钟内拍摄的,并将它们堆叠在一起。这种组织方案足够合乎逻辑,但更令人印象深刻的是所有图像在屏幕上飞舞,然后整齐地堆叠在一起的视觉效果。(这种效果有点像拉斯维加斯赌场里经验丰富的二十一点发牌员在桌子上玩牌。)文件管理通常不会让我开怀一笑,但 Wong 和 Drucker 的照片工具让我倾身屏幕。”


ExtremeTech 评论Longhorn 的 WinHEC alpha 版本,其中任务 切换是“倾斜的窗口列表。你可以实际看到内容。

正如 Winsupersite 展示中的这个 截图所示,想象一下这样的控制面板,其中的元素像下面提到的 Picasa 中的时间轴一样滑动。好吧,也许不适用于企业环境,但它会让家庭用户惊叹,让他们感觉真的进入了 21 世纪。只要功能性和美观性之间取得平衡,我认为这将是一个进步。

你只需要看看 Xbox 或 Windows XP Media Center Edition 的一些消费者 UI,特别是 介绍视频,就可以看到它确实能给人留下深刻印象并具有功能性。

看看 Picasa 和时间线视图。它在平滑动画的滚动时间线上显示您的图片。

许多人真的很喜欢 Apple OS X 界面,我同意这些机器看起来很漂亮,效果也给路人留下了深刻印象。您可以通过 AquaDock 在 Windows XP 上尝试类似的效果。

但对我来说,我很快就想把任务栏找回来;请阅读更多关于 OS X 与 Windows XP 的信息。


那么我们如何平衡两者呢,Hillel Cooperman 和 Tjeerd Hoek 谈论 Longhorn(第二部分)展示了当今 UX 领域正在进行的大量工作、思考和可用性测试。

在微软研究院,他们正在不断改进用户界面,最近的一篇文章“告别普通用户界面”谈到“受电影中计算机工作方式的启发。在电影中,你从不需要登录,从不需要输入文件名,从不需要记住 URL,也不知道什么是浏览器。没有这些人为的区别。事情就这么发生了。

“在 GWindows 中,我们在显示器上方使用两个网络摄像头。机器会感应网络摄像头前方空间中是否有物体。它会在电脑显示器上显示一只小手。你可以抓住一个窗口,移动它,然后放开。或者你可以说‘滚动’,它会映射上下滚动动作。所以你可以结合语音和手势。”

这种东西在研究实验室已经存在多年,它会进入主流吗?我们会开始看到像电影《少数派报告》中那样的显示和互动吗?

用户体验 (UX)

正如我们所说,添加渐变和淡出效果并不能成就一个优秀的应用程序,我认为许多人担心,通过允许开发人员轻松嵌入视频、图形、旋转动画文本和按钮,用户界面可能会变得一团糟。无意冒犯 Chris Anderson 和 Don Box 的 Longhorn 示例!但今天这是可能的,只需回想一下 HTML 页面中的 <marquee> <blink> 标签和 Word 文档中一百零一种不同的字体。

它必须以有用和适当的方式使用。正如 Java UI 有“Java 外观设计指南”一样,Windows 上也有“用户界面开发人员和设计师的官方指南”以及“以用户为中心的设计原则”的基本原理。


我们可以看到微软正在通过“Aero 用户体验指南:PDC 2003 示例”在此领域推出指导

目标是编写一套新书,代号为“Windows 用户体验食谱”,其中将包含优秀 Aero 用户体验设计的指南和示例。这些书将向您展示如何

设计看起来和行为都像新的 Longhorn 应用程序的产品。

  • 提供出色的端到端用户体验。
  • 做一个好的 Windows“公民”。

上面 PDC 2003 编译的采样器链接包含了章节的初步版本,讨论了

它描述了不同组的应用程序,称为“应用程序原型”,展示了 UI 如何在类似组之间共享一些一致性。

例如,一个在线旅游网站可以结合类似网络的展示和丰富的列表视图类型控件。


我们将需要关于创建矢量图形和图标的指南,类似于 创建 Windows XP 图标

它谈到了 Windows XP 图标风格的乐趣、色彩和活力——而且,由于现在有 32 位彩色版本的图标,边缘平滑。每个图标都在矢量程序中渲染,然后用 Adobe Photoshop 进行处理,以创建精美的图像。

这些指南是针对设计师的。因此,他们建议与一位优秀的图形设计师合作,特别是那些有使用矢量或 3D 程序经验的设计师。


很快地触及 WinFS 一下,如果您安装了 Longhorn,请查看文件 c:\windows\system32\winfs\schema\contact.xml,看看联系人模式设计投入了多少思考。即使在早期阶段,它也相当令人印象深刻,并有望继续改进。

那么 XAML 是什么?

正如我们所提到的,它可被视为 Windows 的声明式标记语言,它的特别之处在于

  • 与对象模型的一一对应。
  • 标记和代码在功能和性能上是同等的。

这将实现 UI 创作工具和开发工具之间的互操作,并有助于

  • 保持代码和内容分离。
  • 简化设计师和开发人员之间的协作。


我不会描述所有不同的对象,但我们将有一个非常简单的例子。

在 XAML 中

<Button Width="100px" 
  Background="LightBlue">OK
</Button> 

在C#中

Button b1 = new Button();
b1.Content = "OK"
b1.Background = new SolidColorBrush(Colors.LightBlue); 
b1.Width = new Length(100); 

将给出


第一个问题之一是为什么发明新东西?已经有声明式标记语言了,甚至还有比较它们的竞赛。SVG (Scalable Vector Graphics) 不是矢量图形的标准吗?但正如 Ian Griffiths 在文章《介绍新的 Avalon 图形模型》中指出的那样,那样会失去主要优点之一:与对象模型的一一对应以及与 .NET 框架命名约定的一致性。

还有其他用于描述 UI 的标记语言,甚至还有比较它们的竞赛。我认为值得关注的是 Macromedia Flex,但它的服务器定价似乎太高了。

有关 XAML 的更一般性介绍,请阅读 MSDN 文章“首次了解如何在下一代 Windows 中编写和部署应用程序”。

从位图世界到可伸缩矢量

在 Avalon 中,Windows Shell 的大部分 UI 将以矢量图形绘制。这意味着它们可以缩放而不会出现像素化,就像位图图像那样;这与 Adobe Type Manager/TrueType 使 Windows 中的字体可缩放的方式非常相似。

Paul Thurrott 在他的 评论中给出了一个很好的例子,他在下面展示了这些差异。

位图图像缩放

这并不是真正的矢量图像,而是 OS X 中的一个图标,但我希望它能说明在不同分辨率下,缩放后的图像如何更好地工作

Chris Sells 在他的文章“千里之行始于足下”中谈到了他在学习 Longhorn 时正在编写的新纸牌游戏中的卡片图像的矢量化。

同样,Ian Griffiths 在《介绍新的 Avalon 图形模型》一文中更详细地讨论了 XAML 和矢量路径。

那么 Winforms 是不是一项过时的技术呢?

如果 XAML 是未来,那么人们现在应该投入时间学习 Winforms 吗?好吧,真正的问题是,考虑到 Longhorn 最早也要在 2006 年发布,你能等到那时才发布应用程序供任何人使用吗?

答案可能是否定的,但正如微软的 David Massy 在《为什么要等待 Avalon?》中指出的那样

“你应该等待 Avalon 吗?可能不需要,但你应该考虑 Longhorn 将为开发者带来的所有功能,以及这可能如何让你的应用程序提供更强大的功能和显著改善的易用性。
我强烈鼓励所有开发人员和架构师密切关注我们在 Longhorn 上的进展,以便在它到来时做好准备。当然,也别忘了托管代码在 Longhorn 中的重要性。托管代码和 .NET 框架是 Windows 未来发展的核心。

所以我会说不要等待,今天就拥抱托管代码和 .NET 框架,但要密切关注 Longhorn 将提供什么。”

Robert Scoble 的一篇类似帖子《WinForms 已死的误解被误解了》引起了许多人讨论这个问题。


我在 Zohar Melamed 的博客上回答了一个类似的问题,关于 .NET 功能正在快速废弃,给出了一个类似的答案


回到编码部分!

先决条件 - 安装 PDC 位

恐怕大多数人都没有 PDC 版本,但是如果您或您的公司拥有 MSDN Universal 订阅,您可以下载 alpha 4051 Longhorn 版本。

我也猜测,如果人们参加了 PDC,那么他们在过去几个月里就已经安装并使用过这些版本了。但也许像我一样,在写这篇文章之前,您有一份全职工作要做,只能在家里有空的时候尝试一下,所以您没有太多接触。

阅读文章并了解技术的工作原理固然好,但只有真正尝试编写应用程序,您才能开始学习;这很像通过驾驶考试后学习驾驶,或者几年前我从 COM 世界转向 .NET 时的感受。

您可以在 Winsupersite 上查看 Longhorn PDC 4051 版本的屏幕截图。

方法

我的方法是分别处理树状图计算代码的 C# 实现,使其正常工作,然后研究如何组合和生成 XAML 代码。

通过小步前进,我可以更轻松地调试和更改编码方向,因为我发现了更多,特别是应该在哪里使用哪些 XAML 布局面板

我没有备用电脑来安装和测试 alpha 版本,所以我改用 VMware Workstation 4.0.5 来创建一个虚拟 PC,使用了可用的 30 天评估版。我相信如果您拥有 Microsoft Virtual PC 2004,它也能正常工作。

从规格上看,如果您打算安装所有开发工具、软件开发工具包 (SDK) 和文档,您应该为虚拟会话分配 512Mb 内存和 8Gb 磁盘空间。

请务必遵循发布说明,因为 Longhorn 上的安装顺序非常重要。

还要下载并安装适用于 PDC Visual Studio .NET "Whidbey" 的 XAML IntelliSense 补丁,以改进 XAML 文件的 IntelliSense 编辑。

设计布局 XAML 代码

在 XAML 中绘制矩形和布局是一个反复试验的过程。我对不同类型的布局形状和面板有了一个合理的想法,但具体哪些元素会起作用我不确定,所以只好随便玩玩。


Rectangle 似乎很合适,

<Rectangle Fill="red" StrokeThickness="2" Stroke="darkgray" 
 Height="100" Width="100" /> 

对于绝对定位,可以改为

<Rectangle Canvas.Top="200" Canvas.Left="200" Fill="red" /> 

目前看起来不错,接下来是鼠标悬停动画——我希望灰色边框变为白色。因此,阅读了 使用事件创建翻转效果动画属性触发器,我开始朝这个方向努力。

这意味着我可以在 MyApp.xaml 的样式中声明性地集中定义更改

<Style def:Name="treemapRect"> 
   <Rectangle StrokeThickness="2" Stroke="darkgray" />
   <Style.VisualTriggers> 
      <PropertyTrigger Property="IsMouseOver" Value="True"> 
         <Set PropertyPath="Stroke" Value="white" /> 
         <Set PropertyPath="Cursor" Value="Hand" /> 
      </PropertyTrigger> 
   </Style.VisualTriggers> 
</Style>

请注意,在 Visual Studio 中编辑 XAML 样式时要小心,因为它经常错误地关闭不应该关闭的标签,请在您输入时注意。

为对象分配样式的方法是

<Rectangle Style="{treemapRect}"> 

这对我来说有点奇怪,它与 HTML/CSS 有很多相似之处,但也存在很多差异。我们拭目以待未来会如何发展。

不幸的是,这并没有按预期工作,尽管可能是我的误解。Stroke 颜色变化被忽略了,即使光标改变了。

然而,在 MouseEnter 和 MouseLeave 事件中通过实际的 C# 代码设置值确实更新了边框颜色。

<Rectangle MouseEnter="HighlightRect" MouseLeave="HighlightRect"> 

private void HighlightRect (object sender, 
                            MSAvalon.Windows.Input.MouseEventArgs e) 
{ 
   MSAvalon.Windows.Shapes.Rectangle r = 
                (MSAvalon.Windows.Shapes.Rectangle)sender; 
   MSAvalon.Windows.Media.SolidColorBrush brush = 
                (MSAvalon.Windows.Media.SolidColorBrush) r.Stroke; 

   if ( brush.Color == Colors.White ) 
      r.Stroke = new SolidColorBrush(Colors.DarkGray); 
   else 
      r.Stroke = new SolidColorBrush(Colors.White); 
} 

我确实尝试将 MouseEnter 和 MouseLeave 事件添加到样式中,但出现了“样式声明中不支持事件”的错误。我没有进一步研究这个问题,但我猜测可能可以通过委托来添加 CSS 行为类型的代码?

请注意,由于 XAML 和 C# 代码是 部分类,您不再需要像当前使用 ASP.NET 那样在 C# 中声明标记对象。Whidbey 版本中的 ASP.NET 也是如此;这是对 ASP.NET 1.x 的巨大改进。


另一个问题,这可能是 Longhorn PDC 版本中的一个 bug,也可能不是,是尝试更改 StrokeThickness 值导致布局进入无限循环,从而导致以下错误:



正如你现在可能已经意识到的,Longhorn 的开发就像一次探索之旅,这是 alpha 版本所预期的。一个小插曲是,由于 XAML 比 HTML 更强的类型化,你不能快速注释掉标记。在 HTML 中,我经常将 <… style="font-family: Verdana;"> 更改为 <… xstyle="font-family: Verdana;">。这意味着 xstyle 不是一个有效的属性,因此会被忽略,但在 XAML 中,代码将无法编译。你可以用 <!-- --> 注释掉标签,但如果在测试时不需要剪切粘贴到记事本中以妥善保存,能够快速删除一个属性会很好。

因为我想要矩形内部的文本,我想我会尝试这样做

<Rectangle Fill="red" Width="100" Height="100"> 
   <Text>Hello there</Text> 
</Rectangle> 

但这不起作用,文本不可见,旧的 Windows z 轴顺序概念似乎不是正确的地方。

所以我试了

<Rectangle Fill="red" Stroke="darkgray" StrokeThickness="2" 
   Cursor="Hand" Width="100" Height="100" 
      Canvas.Left="0" Canvas.Top="0" MouseEnter="HighlightRect" 
      MouseLeave="HighlightRect" /> 
<Text Width="100" Height="100" Canvas.Left="0" 
   Canvas.Top="0">Hello there</Text> 

这意味着要对 Left 和 Top 位置进行两次编码,但它确实在 Rectangle 上方绘制了文本。不幸的是,现在 MouseEnter 事件没有触发,因为 Text 控件覆盖了 Rectangle!


然后我想,实际上为什么要费心用 Rectangle 而不直接设置 Text 控件的背景颜色呢?但这不是 Text 控件的属性(可能是文本面板的属性),所以我转而将 Border 控件包装在 Text 控件周围。

请注意 Stroke 和 StrokeThickness 到 BorderBrush 和 BorderThickness 的变化,还有为什么不同控件上的 Fill 和 Background 不同?另外 ID 为什么不遵循 .NET 框架的命名指南,将其称为 Id?我相信这些事情在正式发布之前都会解决。

<Border Canvas.Left="100" Canvas.Top="0" Width="100" Height="100" 
   BorderBrush="darkgray" BorderThickness="2" Background="red" Cursor="Hand"> 
   <Text Foreground="white" TextWrap="Wrap" TextTrimming="CharacterEllipsis" 
      VerticalAlignment="Center" HorizontalAlignment="Center" 
      Width="98%" Height="98%" MouseEnter="HightLightText" 
      MouseLeave="HighLightText">My text inside the Border</Text> 
</Border> 

看起来不错,我认为我们已经有了绘制树状图矩形的基础。因为我们将在代码中创建它们,所以需要将 XAML 转换为 C#。

如果您调试应用程序并查看 obj/Debug/Windows1.g.cs,这是从 XAML 标记生成的 C# 代码,您可以看到实际编译的内容。它很糟糕,但它确实提供了实际调用内容的 ধারণা。

有了这些,C# 代码将是

private void WindowsLoaded (object sender, EventArgs e) 
{ 
   MSAvalon.Windows.Controls.Border b = new MSAvalon.Windows.Controls.Border(); 
   MSAvalon.Windows.Controls.Text t = new MSAvalon.Windows.Controls.Text(); 
  
   // Could use overload on Length to assume pixels 
   Canvas.SetLeft (b, new Length(100, UnitType.Pixel)); 
   Canvas.SetTop (b, new Length(100, UnitType.Pixel)); 
   b.Width = new Length(100, UnitType.Pixel); 
   b.Height = new Length(100, UnitType.Pixel);
   b.BorderBrush = new SolidColorBrush(Colors.DarkGray); 
   b.BorderThickness = new Thickness(new Length(2, UnitType.Pixel)); 
   b.Background = new SolidColorBrush(Colors.Red); 
   b.Cursor = MSAvalon.Windows.Input.Cursor.Hand(); 
  
   t.Foreground = new SolidColorBrush(Colors.White); 
   t.TextWrap = TextWrap.Wrap; 
   t.TextTrimming = MSAvalon.Windows.TextTrimming.CharacterEllipsis; 
   t.VerticalAlignment = MSAvalon.Windows.Media.VerticalAlignment.Center; 
   t.HorizontalAlignment = MSAvalon.Windows.HorizontalAlignment.Center; 
   t.Width = new Length(98, UnitType.Percent); 
   t.Height = new Length(98, UnitType.Percent); 
    
   ((MSAvalon.Windows.Serialization.IAddChild)(t)).AddText("My text 
                                                      inside the Border"); 
    
   t.MouseEnter += new MSAvalon.Windows.Input.MouseEventHandler 
                                                   (this.Highlight); 
   t.MouseLeave += new MSAvalon.Windows.Input.MouseEventHandler 
                                                   (this.Highlight); 
   ((MSAvalon.Windows.Serialization.IAddChild)(b)).AddChild(t); 
  
   oCanvas.Children.Add(b); 
} 

请给我声明性标记,为什么在 MSAvalon.Windows.Media 中是 VerticalAlignment,而在 MSAvalon.Windows 命名空间中是 HorizontalAlignment?

我也很想尝试使用 XAML 中一些高级数据绑定控制功能。

在编写代码和使用 XAML 时,我一直在问自己,它“更好”是因为它新颖有趣,还是真正有所改进?我想一个看待它的方式是,一个具有浮动圆角渐变填充矢量可缩放透明矩形的自动重排文档面板,在 GDI+ 代码下绘制起来会有多困难?我暂时让您阅读 Charles Petzold 的书吧……

<Canvas ID="oInfoCanvas" Width="160" Height="58" Opacity="0"> 
   <Rectangle ID="oInfoRect" RadiusX="4" RadiusY="4" Height="100%" 
       Width="100%" Stroke="#1978B1" StrokeThickness="2" 
       Fill="VerticalGradient #FFC6EBFF #DDFFFFFF" /> 
   <TextPanel Canvas.Left="10" Canvas.Top="6" FontSize="10" 
       FontWeight="Bold"ID="oInfoName"></TextPanel> 
   <TextPanel Canvas.Left="10" Canvas.Top="24" FontSize="10" 
       ID="oInfoSize"></TextPanel> 
   <TextPanel Canvas.Left="10" Canvas.Top="36" FontSize="10" 
       ID="oInfoChange"></TextPanel> 
</Canvas> 

矩形树状图计算代码

计算每个元素大小和颜色的实际代码并不复杂。它就像遵循上面示例中的步骤一样。

我使用 DataSet 将实际数据传递给 Treemap 类以进行绘制,并用于返回计算出的项目值,例如大小、位置和颜色。

public class Treemap
{
   private int width;
   private int height;

   private double changeLimit = 4; // Should really calculate this
                                   // automatically from the given dataset

   ... 

   public Treemap()
   {
      // Constructor
      returnDs = new DataSet();

      DataTable dt = new DataTable();
      dt.Columns.Add("id", typeof(string));
      dt.Columns.Add("name", typeof(string));
      dt.Columns.Add("size", typeof(Single));
      dt.Columns.Add("change", typeof(Single));
      dt.Columns.Add("x", typeof(Single));
      dt.Columns.Add("y", typeof(Single));
      
      ...

      returnDs.Tables.Add(dt);
   }

   public DataSet GetData()
   {
      // Remove temporary calculation columns
      returnDs.Tables[0].Columns.Remove("sizeTmp");
      returnDs.Tables[0].Columns.Remove("changeTmp");
      returnDs.Tables[0].Columns.Remove("widthTmp");
      returnDs.Tables[0].Columns.Remove("heightTmp");
      return returnDs;
   }

CalcMap 函数循环数据,然后计算每个项目的缩放和变化颜色。

public void CalcMap()
{
   CopyValues(); // Copy values from original DataSet to return DataSet
   
   tmp_dWidth = width;
   tmp_dHeight = height;

   double valueScale = 0;
   double changeTotal = 0;
   double dataTotal = 0;

   DataTable dt = returnDs.Tables[0];

   for (int n=0; n < dt.Rows.Count; n++)
   {
      dataTotal += (Single)dt.Rows[n]["sizeTmp"];
   }

   // Scale and set colour change value
   valueScale = ((width * height) / dataTotal) / 100;

   for (int n=0; n < dt.Rows.Count; n++)
   {
      changeTotal += (Single)dt.Rows[n]["change"];
      dt.Rows[n]["sizeTmp"] = valueScale * (Single)dt.Rows[n]["sizeTmp"];
      dt.Rows[n]["changeTmp"] = (255 / changeLimit) * 
                                         (Single)dt.Rows[n]["changeTmp"];

      // Reset if we are over colour range
      if ((Single)dt.Rows[n]["changeTmp"] > 255)
         dt.Rows[n]["changeTmp"] = 255;
      else if ((Single)dt.Rows[n]["changeTmp"] < -255)
         dt.Rows[n]["changeTmp"] = -255;
      
      // Set the green or red change colour value
      if ((Single)dt.Rows[n]["changeTmp"] >= 0)
      {
         dt.Rows[n]["r"] = 0;
         dt.Rows[n]["g"] = (int)(Single)dt.Rows[n]["changeTmp"];
         dt.Rows[n]["b"] = 0;
         dt.Rows[n]["htmlColour"] = ColorTranslator.ToHtml(
                                  Color.FromArgb(0, 
                                  (int)(Single)dt.Rows[n]["changeTmp"], 0));
      }
      else
      {
         dt.Rows[n]["r"] = (int)Math.Abs((Single)dt.Rows[n]["changeTmp"]);
         dt.Rows[n]["g"] = 0;
         dt.Rows[n]["b"] = 0;
         dt.Rows[n]["htmlColour"] = ColorTranslator.ToHtml(
                                  Color.FromArgb(
                                (int)Math.Abs((Single)dt.Rows[n]["changeTmp"]),
                                  0, 0));
      }
   }

这下一段代码本应是递归的,但我使用了简单的 goto 语句作为一种小技巧。根据要绘制的区域的宽度是否大于高度来决定是垂直绘制还是水平绘制。

然后尝试绘制由起始到结束范围定义的当前元素。Try 函数尝试放置项目并返回最后一个放置项目的纵横比。

如果此纵横比比以前的纵横比差,那么我们锁定以前的布局位置,设置新的剩余区域以进行布局并重新开始。

   int start = 0;
   int end = 0;

   bool vert;

   Single aspectCurr = 999;
   Single aspectLast;
   
   vert = DrawVert(tmp_dWidth, tmp_dHeight);

startover:

   while (end != dt.Rows.Count)
   {
      aspectLast = Try(start, end, vert);

      // Is aspect ratio worse than previous ratio?
      if ((aspectLast > aspectCurr) || (aspectLast < 1))
      {
         Single currX = 0;
         Single currY = 0;

         // Lock the previous items in place
         for (int n = start; n < end; n++)
         {
            dt.Rows[n]["x"] = offsetX + currX;
            dt.Rows[n]["y"] = offsetY + currY;
            
            if (vert)
               currY += (Single)dt.Rows[n]["height"];
            else
               currX += (Single)dt.Rows[n]["width"];
         }

         if (vert)
            offsetX += (Single)dt.Rows[start]["width"];
         else
            offsetY += (Single)dt.Rows[start]["height"];
         
         tmp_dWidth = width - offsetX;
         tmp_dHeight = height - offsetY;

         vert = DrawVert(tmp_dWidth, tmp_dHeight);
         start = end;
         end = start;
         aspectCurr = 999;

         goto startover;
      }
      else
      {
         // Store newly calculate sizes
         for (int n = start; n <= end; n++)
         {
            dt.Rows[n]["width"] = dt.Rows[n]["widthTmp"];
            dt.Rows[n]["height"] = dt.Rows[n]["HeightTmp"];
         }
         aspectCurr = aspectLast;
      }

      // try to draw another item
      end++;
   }

   // Set each item in the positions in the remaining area
   Single currX1 = 0;
   Single currY1 = 0;

   for (int n = start; n < end; n++)
   {
      dt.Rows[n]["x"] = offsetX + currX1;
      dt.Rows[n]["y"] = offsetY + currY1;

      if (vert)
         currY1 += (Single)dt.Rows[n]["height"];
      else
         currX1 += (Single)dt.Rows[n]["width"];
   }
}
Try 函数测试在可用空间中设置总项目大小,并返回我们放置的最后一个项目的纵横比。
private Single Try(int start, int end, bool vert)
{
   Single total = 0; 
   Single aspect = 0;
   Single localWidth;
   Single localHeight;

   for (int n = start; n <= end; n++)
   {
      total += (Single)returnDs.Tables[0].Rows[n]["sizeTmp"];
   }

   // Scale as needed for the width or height
   if (vert)
   {
      localWidth = total / tmp_dHeight * 100;
      localHeight = tmp_dHeight;
   }
   else
   {
      localHeight = total / tmp_dWidth * 100;
      localWidth = tmp_dWidth;
   }

   for (int n=start; n <= end; n++)
   {
      if (vert)
      {
         returnDs.Tables[0].Rows[n]["widthTmp"] = localWidth;
         returnDs.Tables[0].Rows[n]["heightTmp"] = (Single)(localHeight * 
                 ((Single)returnDs.Tables[0].Rows[n]["sizeTmp"] / total));
      }
      else
      {
         returnDs.Tables[0].Rows[n]["widthTmp"] = (Single)(localWidth * 
                 ((Single)returnDs.Tables[0].Rows[n]["sizeTmp"] / total));
         returnDs.Tables[0].Rows[n]["heightTmp"] = localHeight;
      }

      aspect = Math.Max((Single)returnDs.Tables[0].Rows[n]["heightTmp"] / 
                  (Single)returnDs.Tables[0].Rows[n]["widthTmp"],
                        (Single)returnDs.Tables[0].Rows[n]["widthTmp"] / 
                  (Single)returnDs.Tables[0].Rows[n]["heightTmp"]);
   }

   return aspect;
}

private bool DrawVert(Single width, Single height)
{
   return width > height;
}

Using the Code

实际使用 Treemap.cs C# 代码并不太糟糕。

创建一个类实例,设置宽度和高度,将包含 id、name、size 和 change 列的 DataSet 分配给 DataSource 成员。调用 CalcMap 计算布局,然后调用 GetData 检索包含原始列和附加 x、y、width、height、htmlcolour、r、g 和 b 列的 DataSet。

然后遍历返回的 DataSet,使用 x、y、width 和 height 值绘制项目。

Treemap.Treemap map = new Treemap.Treemap();

map.Width = (int)oMainCanvas.Width.Value;
map.Height = (int)oMainCanvas.Height.Value;

map.DataSource = LoadData();

map.CalcMap();
ds = map.GetData();

for (int n = 0; n < ds.Tables[0].Rows.Count; n++)
{
   MSAvalon.Windows.Controls.Border b = new MSAvalon.Windows.Controls.Border();

   Canvas.SetLeft(b, new Length(
          Double.Parse(ds.Tables[0].Rows[n]["x"].ToString()), 
UnitType.Pixel)); Canvas.SetTop(b, new Length( Double.Parse(ds.Tables[0].Rows[n]["y"].ToString()),
UnitType.Pixel)); b.Width = new Length( Double.Parse(ds.Tables[0].Rows[n]["width"].ToString()),
UnitType.Pixel); b.Height = new Length( Double.Parse(ds.Tables[0].Rows[n]["height"].ToString()),
UnitType.Pixel); ... }

必须为代码的质量和命名道歉,我真的应该重做和重构很多,但是一旦它工作了,我就不太想在 VMware 会话中修改它,因为它不是最好的调试设置。记住这只是一个演示,所以请不要根据设计来评判我!

我本来希望不要使用 DataSet 作为视图和控制器之间的数据传输对象,我以为我会尝试一下以求改变,但经过所有类型转换和调试噩梦(即使有数据可视化器)之后,我还是会坚持使用合适的类。

示例数据和 XPath

我在演示应用程序中使用的示例行业、部门和公司信息是从 Yahoo Finance 行业浏览器网站下载的 .csv 格式信息。

然后我编写了一个快速的 Excel VBA 宏,将这些数据导出为 XML 字符串;我只是随意创建了该模式。

<?xml version="1.0" encoding="utf-8" ?> 
<Industries Date="8-May-2004" Source="Yahoo Finance" 
   Size="Market Cap (Billions)" Change="1 Day Price Change (%)"> 
 <Industry Id="I1" Name="Services" Size="4393.54" Change="-1.864"> 
  <Sector Id="S1" Name="Communications Services" Size="1640.2" Change="-1.8" /> 
  <Sector Id="S2" Name="Broadcasting & Cable TV" Size="497" Change="-1.22"/> 
  <Sector Id="S3" Name="Retail (Department & Discount)" Size="357.4" 
          Change="-1.35" /> 
  <Sector Id="S4" Name="Real Estate Operations" Size="242.3" Change="-3.4" /> 
  <Sector Id="S5" Name="Printing & Publishing" Size="216.1" Change="-0.82"/> 
  <Sector Id="S6" Name="Retail (Specialty)" Size="208.8" Change="-2.36" /> 
  <Sector Id="S7" Name="Business Services" Size="195.8" Change="-0.4" /> 
  <Sector Id="S8" Name="Retail (Grocery)" Size="162.8" Change="-1.42" /> 
  <Sector Id="S9" Name="Retail (Home Improvement)" Size="120.4" Change="-3.59"/> 
  ... 

这意味着我可以使用 XPathNavigator 来选择我想使用简单 XPath 表达式显示的集合,例如

/*/* to get all the industries. 
/*/*[@Id='I1']/* to get all the sectors for the I1 industry 
/*/*[@Id='I3']/*[@Id='S1']/* to get all the companies in a sector, industry 

并用这个加载数据

XPathDocument doc = new XPathDocument(@"c:\YahooData.xml"); 
  
// Create an XPathNavigator 
XPathNavigator nav = doc.CreateNavigator(); 
  
// Create a node interator to select nodes and move through them (read-only) 
XPathNodeIterator Iterator = nav.Select(currXPath); 
  
while (Iterator.MoveNext()) 
{ 
   dr = dt.NewRow(); 
   dr["id"] = Iterator.Current.GetAttribute("Id", nav.NamespaceURI); 
   dr["name"] = Iterator.Current.GetAttribute("Name", nav.NamespaceURI); 
   dr["size"] = Iterator.Current.GetAttribute("Size", nav.NamespaceURI); 
   dr["change"] = Iterator.Current.GetAttribute("Change", nav.NamespaceURI); 
   dt.Rows.Add(dr); 
  
   textOverview.TextRange.Text = Iterator.Current.Name + " Overview"; 
} 

如果您愿意,可以轻松地将我的 XML 文件替换为您自己的文件。

应用程序布局设计

请不要将我的演示应用程序作为 UI 设计和 Longhorn 期望的良好示例。这是我第一次尝试使用 XAML 进行表单设计,并且在没有任何先验知识的情况下开始是相当困难的。

看看最终的 XAML 编辑设计时工具会是什么样子,这将很有趣。

理想情况下,它们将是 Visual Studio 与 Macromedia Dreamweaver、Fireworks 和 Flash 的结合,并带有一点 discreet 3ds maxAlias Maya 的 3D 支持。所有这些工具都可以获得评估版本来试用,实际上我为了这篇文章也试用过。

鉴于 XAML 作为格式良好的 XML 文件的性质,它应该易于“工具化”,并有望支持向导以帮助将内联标记优化为集中式样式。

矩形树状图概念视频

如开头所述,我希望那些没有安装 Longhorn PDC 版本的人也能看到应用程序的运行情况。

我遵循了 Microsoft Longhorn 概念视频的风格,如果人们以前没有下载过,这些视频是必看的。

因此,我录制了自己点击应用程序的过程,保存为 .avi 文件,然后使用 Windows Movie Maker 2 添加了一些效果和转场,最后制作成 .wmv 文件;您需要 Microsoft Windows Media Player 9 才能播放此剪辑。

我还模拟了如果我使用一些 XAML 动画和 Flash 中的过渡效果,缩放效果会如何工作,所以这有点作弊。

下载视频演示 - 3762 Kb 希望您喜欢观看!

示例应用程序

您可以从 bin\debug 目录启动应用程序 XAMLTreemaps.exe,并确保文件 YahooData.xml 位于 C:\。

加载后,点击窗口右侧的“加载数据”按钮。

然后注意,当您将光标移动到不同区域时,浮动窗口中会显示元素的附加元数据。点击所需的行业以深入查看数据到部门级别。

我只添加了“软件和编程”部门的数据,所以如果您点击它,它将显示该部门下的公司。否则,它将再次缩小到顶级。

我本应该使用 XAML 窗口样式的导航功能,但目前做到这一步已经足够了。

此外,我获取数据的那天对金融市场来说相当糟糕,因为大多数行业/公司的价格变化都是负面的。但它仍然应该为您提供一个很好的例子,说明您如何一眼就能看出哪些行业和股票表现积极或消极。

如果您调整窗口大小,则必须再次单击“加载数据”,因为我没有找到将大小更改事件与面板关联的方法。


有很多方法可以改进应用程序,例如更好地处理名称不完全匹配的情况,自动确定最佳颜色范围。但这只是一个演示,旨在帮助您理解概念。


可视化与交互技术

现在,正如承诺的那样,快速浏览并提及我最近见过的一些可视化和交互技术。

请注意,我与这些产品或公司均无关联,但我列出它们是因为我认为它们很有趣。

在桌面层面,微软研究部门有一些他们称之为 任务画廊的截图和视频剪辑。

这是一个始于 1999 年的研究测试项目,他们用它来了解不同的隐喻、交互技术和底层技术基础设施如何用于应用程序重定向。我们不会在未来版本的 Windows 中看到这一点,但多桌面和分类的元素是强大的概念。

微软 商业和娱乐可视化与交互 (VIBE) 团队页面上有更多的研究项目。他们将团队的使命描述为设计优雅的可视化和交互技术,涵盖各种设备和显示器。Patrick Baudisch 有一个拖放增强的想法,以及其他您可以在 Flash 中尝试的想法。

 

来自 SunProject Looking Glass 也旨在发展当今的 2D 桌面。

“如果窗户是半透明的,这样您就可以同时看到您正在处理的多个窗户呢?如果您可以直接在您正在查看的网页上给自己贴一张便条呢?如果您的 CD 或电影数据库变成一个 3D 点唱机,标题与图像结合在一起,让您比以往任何时候都更容易找到您想要的东西呢?”

有更多的截图和令人印象深刻的视频演示可供观看,绝对值得一看。

 

另一个桌面概念是 SphereXP,它是一个用于 Microsoft Windows XP 的 3D 桌面替代品。它仍处于早期阶段;观看视频剪辑并亲自尝试。


如果您观看这个 NBC 视频采访 微软研究院,他们谈论数字摄影(大约一分钟左右)。关于如何使用新的开发中的媒体浏览器查找和组织图片,该浏览器允许您按日期、室内或室外——几乎任何您选择的条件搜索和排列照片和视频剪辑。将鼠标悬停在图片上会显示一个大的缩略图。将所有内容整理好,然后创建文件夹并将照片和剪辑拖放到您想要的位置。


现在来看一些您可以整合到应用程序中的更简单的图形元素。

Chris Sells 谈到 Edward Tufte 的信息可视化工作,“我相信 Avalon 的最大意义在于它为我们提供了更强大的工具来处理数据可视化和操作。

一个例子是 SparklinesSean Gerety 指出,通过它您可以增强数据显示,例如这样

你可以只显示最近的数据

或一个小型滚动时间序列图表,其中灰色显示预期限值,以及其他测量值,以便于比较和阅读。

一个有点奇怪的故事,在我看到这个的第二天,我在工作时与一个分析团队交谈,注意到他们有一本 Edward Tufte 的书。聊了一会儿之后,我提到了 sparklines,结果发现他们刚刚在一个网站上实现了它们,用于比较债券曲线。

 

Ben Fry 的这个怎么样?它提供了一种更令人满意的方式来填写地址组合框,当你输入邮政编码时,它会突出显示或放大到该区域。提示:按下“z”并尝试打开缩放功能。


一家名为 Inxight 的公司有许多产品,它从 Xerox PARC 分离出来,他们将其业务重点描述为“从非结构化数据源中发现信息”。

其中一个产品是 Inxight TableLens,“它提供表格数据的图形显示,代表了一种探索数据集的新方式——即使是那些太大而无法以表格或 XY 图形式查看和理解的数据集。通过创建 TableLens 对象,用户可以与他们的数据进行交互,以发现模式和趋势以进行进一步探索。查看超过 100 列和 65,000 行数据的图形表示——所有这些都在同一个屏幕上——使数据趋势和相关性一目了然。

按照导览,它解释了如何查看、排序、分组、放大数据。然后尝试使用交互式演示来查看前 100 部电影航班延误信息,可以很容易地找到通常需要一段时间才能分析出的问题的答案。

他们曾经有一个名为 Inxight Eureka 的独立桌面版本,可以用来查看 .csv、.xls 等文件,但遗憾的是,该版本已停产。

Inxight 还推出了一款名为 TimeWall 的产品,“传统的时钟工具是静态、不灵活的,不适合显示大量信息,而 Inxight TimeWall 则将时间显示在一个动态的三维‘墙’上。它使分析师、决策者和其他人能够更快、更明智地做出决策,因为相关信息触手可及。”

它让您更容易找到上周写的文档,并且与 Microsoft Outlook 中的日记功能非常相似。

但当它与多个数据源结合使用时,它会走得更远,您可以跨日期或事件查看模式。


NetMap Analytics 的 NetMap 是一个有趣的应用程序。它看起来非常巧妙,但遗憾的是,他们没有任何交互式演示,只有一个 Kevin Bacon 的六度分离演练。

其理念是,例如,您拥有关于人员、保险索赔、地址、电话号码、银行账户等信息。您可以将这些关系连接起来并寻找模式,即使它们相隔几个分离,也可以放大并更深入地挖掘。

他们的网站上有一份不错的 PDF 文档,更详细地解释了这一理念及其在调查中的应用。该软件已被澳大利亚警方用于锁定系列背包客谋杀案

Daisy Analysis 公司的一款名为 Daisy 的类似产品也基于相同的原理。它将各种关系连接起来,并寻找强烈的模式。

您可以下载试用版并尝试他们提供的一些示例数据集。

在 Winsupersite 的早期 Longhorn alpha 屏幕截图中,联系人以旋转木马视图显示。也许我们会看到类似这样的东西,利用 WinFS 元数据以图形方式显示关系?


一个有趣的鱼眼技术用于查看数据的是 Datelens。这款用于 PDA 等小型手持设备的日历应用程序使用日期的鱼眼表示以及紧凑的概览。用户控制可见时间段,这使他们能够查看概览,轻松浏览日历结构,并发现模式和异常。

我个人没有使用它来查看日历,但 Longhorn 概念视频《商业房地产》中也使用了这种缩放鱼眼技术。

IBM 的协作用户体验研究小组正在进行一些关于历史流的有趣工作,特别是维基条目的变化。


最后,虽然有点离题,但仍然很有趣的是,伦敦地铁图是如何由 Harry Beck 重新设计,以更好地显示信息,但实际上在地理上并不准确。网站 《伦敦地铁图的历史》有图片和解释,介绍了地图多年来的变化。

请注意,这些地图版权归伦敦交通局所有,这就是为什么我使用了小图片并链接它们供您正确查看的原因。

从 1932 年的这个

Copyright Transport for London

到今天的现代电路示意图表示

Copyright Transport for London

伦敦交通局有一部名为 “真实地铁” 的 Flash 电影,展示了线路如何在两种地图风格之间重新定位。

总结

那么现在我们以简短的总结来结束本文,内容包括矩形树状图代码未来可能增强的功能以及一些进一步阅读的参考资料。

进一步增强

主要探讨本文中显示的矩形树状图实现可能进行的更改

  • 无需重新计算布局大小或更高效地执行。
  • 更简洁的代码,特别是重构 goto 语句并替换为递归方法。
  • 移除使用 DataSet 作为传输数据对象,以消除一些类型转换。
  • 为变化变量添加更好的颜色范围,而不是让开发人员设置 +/- 值,自动决定分布和最佳范围。
  • 支持数据集中缺失的值,使其不会影响计算。
  • 当缩小视图时,在树状图内部将较低层次的信息显示为树状图。
  • 改进计算布局代码与渲染的分离,以便更容易插入 HTML、GDI+ 渲染器。
  • 打包代码以便更好地重用。
  • 为应用程序提供导入功能,以便用户可以加载自己的数据。
  • 使用动画在钻取数据时显示缩放效果。
  • XAML 速度改进和优化。
  • 使用 Longhorn 窗口样式中的导航按钮向前和向后移动。
  • 转换为 Longhorn 的侧边栏磁贴。
  • 提供渲染到 HTML、GIF + 图像映射等的代码。

关注点

几个月前我买了一台额外的显示器,它确实有助于开发和阅读文档,结合 UltraMon,它确实提高了生产力。

我还尝试使用 Whidbey 中一些自动化的重构支持来“提取方法”处理部分代码,但它似乎在我的项目中不起作用。抱歉,如果这个演示中存在许多糟糕的“代码异味”,可能需要重构。

如果您还没有读过 Martin Fowler 关于《重构》的书,我绝对推荐。

部分类 是 XAML/C# 编程的巨大改进,无需为每个控件添加保护成员变量,从而减轻了开发人员的痛苦负担。

将 C# Treemap.cs 类拿出来,然后添加在 Winforms 应用程序、Java applet 或 HTML 中使用绝对定位的 DIV 标签集来渲染地图的支持,相对来说会更容易。

参考文献

有关信息可视化的未来阅读,请参考此书《信息可视化》。

结论

我希望这篇文章对您有所帮助,如果太长,再次表示歉意。每天阅读博客新信息时,总觉得有更多东西可以补充。

现在,也许您想在下一个项目中尝试一些可视化技术,以帮助您自己或您的用户做出更好的决策。


请注意,矩形树状图布局思想并非由我本人提出,而是由埃因霍温理工大学数学与计算机科学系的 Mark Bruls、Kees Huizing 和 Jarke J. van Wijk 在他们的研究论文中设计的。在本文中,我只是将他们的思想转换为 C# 代码,并使用 XAML 作为显示渲染语言,这同样可以很容易地修改为在 GDI 或 HTML 中绘制。

感谢 Microsoft UK MSDN 的 Stephen Turner 几周前提供的 Avalon 演示,由于我使用 XAML 已有一段时间,很高兴听到对 RetainedVisual 等概念的真实解释。


在编写代码和撰写本文时,我使用了 MSDN 网站上的 Longhorn SDK,但就在上周,由于在 WinHEC 会议上发布了新版本,他们更新了它。其中一个主要变化是将命名空间 MSAvalon 更改为 System.Windows,因此如果您尝试从 PDC 版本移植代码,请注意这一点。

所以 XAML 是另一个需要学习的新技术,而且它还需要几年时间才能成熟,但如果你是一名 Windows 开发者,我认为这是朝着将 Web 开发的便捷性与 Windows 平台的丰富性相结合的积极一步。


微软有很多 Longhorn 宣传者希望激发人们对 Longhorn 及其技术的热情,而当它还很遥远时保持这种势头将是一个挑战,我希望我在这里有所帮助。

 

再次感谢您的阅读,如果您有任何反馈,请告诉我。

历史

2004 年 5 月 14 日 – 首次发布到 Code Project。
2004 年 6 月 3 日 - 对超链接格式进行了细微更改,并添加了图片上视频演示的超链接。

© . All rights reserved.