通过ASP.NET理解WPF






4.87/5 (43投票s)
展示了如何通过ASP.NET轻松理解某些WPF概念。
引言
和许多人一样,我很难掌握WPF,因为它在编写桌面应用程序时似乎非常“陌生”。它看起来非常不同,我无法应用我已有的知识——然后有一天,我突然明白了。我一直从错误的角度来处理这个问题,完全错误。通过应用ASP.NET的思维方式,我可以将我知道的东西与WPF联系起来。显然,WPF提供的远不止这些,但它给了我一个良好的开端。
我们不会深入探讨WPF。我将展示用ASP.NET和WPF编写的同一个应用程序,并看看代码的不同部分是如何关联的。我们还将看看WPF的一些根本区别,尽管表面上看它们是相同的。
本文并非旨在研究无状态和有状态应用程序之间的差异。我们不会担心往返和状态维护等问题。
概述
在我们继续之前,让我们来看看我们要创建的应用程序。这是一个从XML文件读取数据并在列表中显示的简单应用程序。里面没有什么复杂的东西,我们将完成所有“巧妙”的工作。我们要绑定到数据如下所示:
<?xml version="1.0" encoding="utf-8" ?>
<People>
<Person Name="Josh" Handle="RockStar" IQ="10000" />
<Person Name="Sacha" Handle="The Bloginator" IQ="10000" />
<Person Name="Karl" Handle="The MoleMan" IQ="10000" />
<Person Name="Pete" Handle="Pretender to the throne" IQ="10" />
</People>
ASP.NET应用程序看起来是这样的:
WPF应用程序看起来是这样的:
ASP.NET应用程序
这里显示的是ASP.NET应用程序的代码:
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Sample App</title>
<style type="text/css" media="all">
td
{
font-family : Tahoma;
font-size : 10px;
}
.iqStyle
{
font-family : Verdana;
font-size : 14px;
font-style : italic;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataSourceID="XmlDataSource1" ShowHeader="False">
<Columns>
<asp:BoundField DataField="Name" />
<asp:BoundField DataField="Handle" />
<asp:BoundField DataField="IQ" ItemStyle-CssClass="iqStyle" />
</Columns>
</asp:GridView>
</div>
<asp:XmlDataSource ID="XmlDataSource1" runat="server" DataFile="~/Sample.xml"
XPath="/People/Person"></asp:XmlDataSource>
</form>
</body>
</html>
正如你所见,它并不复杂。基本上,我们创建了一个XmlDataSource
并将其绑定到一个GridView
。我们手动添加了几种样式来控制格式,但这里没有复杂的代码。绑定在这里都已为我们处理好了。
WPF应用程序
现在,让我们来看看WPF版本的代码:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2006"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
x:Class="WpfSampleApp.Window1"
x:Name="Window"
Title="Sample App"
Width="380" Height="240">
<Window.Resources>
<XmlDataProvider x:Key="PeopleSource" d:IsDataSource="True" Source="Sample.xml"/>
<Style TargetType="ListBox">
<Setter Property="Control.FontFamily" Value="Tahoma" />
<Setter Property="Control.FontSize" Value="10" />
</Style>
<Style x:Key="FontStyle">
<Setter Property="Control.FontFamily" Value="Verdana" />
<Setter Property="Control.FontStyle" Value="Italic" />
<Setter Property="Control.FontSize" Value="12"/>
</Style>
<DataTemplate x:Key="PersonTemplate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Width="40" Grid.Column="0"
Text="{Binding Mode=OneWay, XPath = @Name}" />
<TextBlock Width="130" Grid.Column="1"
Text="{Binding Mode=OneWay, XPath=@Handle}" />
<TextBlock Width="Auto" Grid.Column="2"
Text="{Binding Mode=OneWay, XPath = @IQ}"
Style="{StaticResource FontStyle}" />
</Grid>
</DataTemplate>
</Window.Resources>
<Grid x:Name="LayoutRoot">
<ListBox Padding="3" HorizontalAlignment="Left" Width="Auto"
ItemTemplate="{DynamicResource PersonTemplate}"
ItemsSource="{Binding Mode=Default, Source={StaticResource PeopleSource},
XPath=/People/Person}" VerticalAlignment="Top" Height="Auto"/>
</Grid>
</Window>
我使用Expression Blend来组合这个(提示——如果你认真对待WPF,那么你真的需要获取Blend;它会让你的生活变得轻松很多)。它使用XmlDataSource
绑定到一个ListBox
,我们将对其进行格式化以显示XML文件中的数据。再次注意,我没有写一行C#代码——所有这些都是在XAML中完成的。
样式
如前所述,我们在ASP.NET应用程序中创建了几种样式。同样,我们在WPF应用程序中创建了几种样式,它们做了大致相同的事情。在本节中,我们将看看我们创建的两种类型的样式。
类型选择器
在CSS中,类型选择器允许你将样式匹配到文档树中该类型的所有实例。因此,我们将把每个TD
元素的字体更改为10px Tahoma。
WPF允许你通过创建应用于特定TargetType
的样式来实现相同的功能。在我们的示例中,我们将窗口中每个ListBox
的字体大小更改为10号Tahoma。
细心的读者会注意到,我没有说ListBox
中的字体大小是10像素。这是WPF中需要适应的第一个变化之一,即WPF是分辨率无关的。这意味着我们不再以像素为单位来思考问题——所以,在96DPI显示器上的一英寸按钮,在140DPI显示器上仍然是一英寸按钮。
命名样式
在ASP.NET应用程序中,我们创建了一个命名样式,将字体更改为12px斜体Verdana。同样,WPF也允许我们设置一个命名样式,将字体更改为12号斜体Verdana。要在ASP.NET中应用样式,我们使用了ItemStyle-CssClass="iqStyle"
。在WPF中应用样式同样简单;这里我们使用Style="{StaticResource FontStyle}"
。{...}
部分利用绑定来实际应用值——StaticResource
提供对先前加载资源的引用,因此在此处内联样式很有用。WPF允许你创建等同于外部样式表的样式。Josh Smith提供了关于使用外部资源的优秀教程。(我最喜欢的是这个。)
数据绑定
在这两个应用程序中,我们都使用XPath从XML中检索值。在这两种情况下,我们都创建了一个DataSource来链接到XML文件,然后说明了我们希望如何显示它。
在ASP.NET中,我们声明想要使用一组BoundField
来显示数据的每个部分。
这里使用的WPF功能更强大,因为我们将项目的显示方式与其实际显示的容器分开了。这意味着我们可以在不同的容器中使用相同的模板——从而保持一致性并消除重复。在WPF代码中,模板是DataTemplate
部分的内容。它表明我们希望每个项目显示一行数据,包含三列。每个项目都显示在一个TextBlock
中,它是一个通用的文本类,并通过单向数据绑定绑定到特定元素。
在我们的示例中,DataTemplate
的实际使用者是ListBox
。ItemsSource
告诉运行时我们想将数据源中的数据绑定到我们的列表框。如前所述,DataTemplate
中的Grid代表一行数据。ItemTemplate
简单地告诉应用程序为每一行应用哪个模板,并且在某种程度上,可以认为它类似于GridView
上的RowDataBound
方法。因此,对于每一行数据,我们将创建一个由PersonTemplate
表示的Grid。
结论
我希望这篇文章能让你对WPF产生足够的兴趣,让你想开始尝试。如果你有ASP.NET的经验,那么WPF的某些元素会更容易理解。WPF背后的团队显然从ASP.NET中学到了很多经验,并将其运用得很好。通过从ASP.NET中应用程序开发的角度来思考WPF元素,许多概念将突然变得清晰起来。显然,我省略了很多关于如何使用WPF的细节,而且我并不是说WPF应该用于Web开发,但它展示了那种特定的思维方式可以给你一个良好的开端。
可能,你将面临的最大的初步障碍是熟悉WPF如何利用绑定,这远远超出了仅仅绑定到数据库中的项。一旦你开始欣赏它如何让你绑定到应用程序中的几乎任何东西,你就会意识到你可以在不编写任何C#(或VB.NET)的情况下完成多少工作。
推荐阅读
我不会链接到文章,但我可以建议你阅读Josh Smith、Karl Shiflett和Sacha Barber的WPF文章吗?他们创作了一些很棒的教程,适合所有水平的读者。