wpf 学习

这是一篇关于WPF技术的学习系列文章,旨在帮助读者快速掌握WPF,成为技术先锋。作者分享了两个月的学习体会,指出WPF是实用且易学的,但也强调学习路径的重要性。文章分为两部分,第一部分介绍了什么是WPF,通过创建简单的UI程序来展示WPF的基本用法,如拖放控件、事件处理等。第二部分开始解剖最简单的GUI程序,引导读者学习XAML语言,通过实例解析代码,讲解XAML的元素嵌套和名称空间等概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文:http://www.cnblogs.com/_hwh_/category/178977.html

深入浅出WPF(1)——什么是WPF

 
小序:

Hi,大家好!几乎两个月没有写技术文章了。这两个月,我在学习WPF。回顾一下两个月的学习历程,有两个感觉——第一,WPF是一项非常实用又简单易学的东西,它将成为未来MS平台上快速开发的主流趋势;第二,WPF的学习比较讲求路径,如果没有一个比较好的路径,学习起来可能比较慢,主要原因是它像是一种ASP.NET与Windows Forms的“杂交品种”,里面有很多内容与前两者似像非像,同时还有很多新内容的引入。

本系列文章的主要目标是:帮助大家学习WPF技术,快速成为这项技术的开路先锋。在此,我借优快云一块宝地,把这两个月来学习到的东西做一个整理,奉献给大家。希望大家能喜欢。BTW,本系列文章的风格将一改以前长篇累牍的样式,改变为非常短小的篇幅,每篇文章一两个知识点,小步快跑、天天积累。这样,我写着不累,你看着也不累。

在我两个月的学习中,我的同事们——Anstinus、 Mathew、 Allen、 ChengSong、 Edward和Mike——他们像战场上的战友一样给了我无数的帮助。在这里,我向这些同事表示深深的感谢和敬意。还有我的搭档——大美女Yan,和你在一起工作很开心。

 

正文:

什么是WPF

 
WPF,Windows Presentation Foundation也,译过来就是“Windows呈现基础”,你看它的目的非常明确,就是用来把数据“显示”给用户看的(说白了就是用来做UI的)。如果只是给用户显示几串文本、两三张图片或者几个表格那WPF就太糗了,幸乎,WPF可不是这等素食动物——大家都见过Flash动画吧,WPF的显示能力丝毫不亚于Flash以及Flash的同门师弟Flex+AIR(某建筑公司产品)。
 
为什么会有WPF
 
“微软出点儿什么新东西,我就得跟着跑!”我也曾这样抱怨过。不过,当大量的工作任务压在头上的时候,我终于感觉到——每一次技术(包括理念、架构、语言、工具)的更新都带来了巨大的工作效率提升。的确,我们需要花些时间来搞懂那些看起来乱糟糟的新概念,但搞明白之后——坦白地讲,在有人带的情况下,这并不是什么难事——我们就能用非常少的代码来换取先前技术大量代码才能获得的功能。似乎代码量是开发团队中一切糟糕问题的罪魁祸首,so,明白了?
 
对于WPF是如何减少代码量的,后面有一个例子。但WPF绝不是一个只能帮我们减少代码量的家伙,更重要的是,它还能帮我们把程序的界面和功能逻辑近乎彻底地剥离——in a nutshell,把你的程序变成一只香蕉或者橘子——“皮”是可以从“瓤”上剥下来的,一旦某天用户说:“这个橘子能不能看起来像是个香蕉?”你就可以为你的橘子瓣儿裹上漂亮的进口香蕉皮再开出一个更漂亮的价码。
 
WPF是怎样做到的
 
使用WPF技术开发产品,程序的“皮”,也就是UI,是使用XAML语言来“画”出来的;而程序的“瓤”,也就是功能逻辑,可以由程序员来选择使用C#/VB.NET/C++.NET等托管语言来实现。
 
对于程序员们来说,C#/VB.NET/C++什么的已经是耳熟能详。XAML是什么呢?简言之,XAML(读音为“zamel”,近似于“咋没有”)是XML语言的一个衍生物,它的语法基本上与XML语言完全一致;它的功能就是专门用来设计和实现程序的UI;它看起来和HTML语言非常像,无论你是程序员还是美工人员,只要你设计过网页,那学习XAML对你来说都是小菜一碟儿。而且,XAML可不像HTML和XHTML那样只能呆在Web开发领域——XAML对于Web开发和桌面开发是“通吃”的,从Web程序改成桌面程序或者反过来,所付出的工作量惊人的小,而且由于UI与逻辑完全分离,逻辑代码几乎不用改动——这意味着两种开发的边界渐渐消失,两类设计人员和程序员将会染指“彼岸”、拿到更多的项目、挣更多的钱。
 
WPF之前,无论是Win32 API编程、使用MFC编程还是Windows Form编程,美工(设计人员)设计出来的界面都需要由程序员使用Visual Studio来实现。程序员不是美工,VS也干不过PS……越俎代庖永远是高效分工的大敌。如今,为了支持WPF程序设计,微软推出了专门的、使用 XAML语言进行UI设计工具——Expression Studio,使用它就像使用PhotoShop和Dreamweaver一样,设计出来的结果保存为XAML文件,程序员可以直接拿来用;当UI有变更时,程序员只消用新版XAML文件替换旧版即可。
 
XAML小试牛刀
 
让我们实现这样一个小小的需求,完全使用XAML代码而不需要C#来参与。用户需要一个窗口,里面有一个TextBox和一个Button,并且窗口的背景是蓝色的过渡色。
 
 
 
我保证:真的一行C#代码都没写!是不是足以让Windows Form程序员艳羡不已?!
 
一切实现都是使用XAML语言完成的——你可以使用Visual Studio 2008的XAML设计器来完成,也可以使用Expression Studio来更专业地完成设计。下面是它的XAML代码,你现在只需要看个大概,后面的文章里,我会一个词一个词为你解释。
 

<Window x:Class="WpfApplication1.Window1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Window1" Height="300" Width="300">

    <Grid>

        <Grid.Background>

            <LinearGradientBrush>

                <GradientStop Offset="0" Color="Blue"></GradientStop>

                <GradientStop Offset="0.5" Color="LightBlue"></GradientStop>

            </LinearGradientBrush>

        </Grid.Background>

        <TextBox Height="23" Margin="10,10,10,0" Name="textBox1" VerticalAlignment="Top" Text="Hello WPF!" />

        <Button Height="23" HorizontalAlignment="Right" Margin="0,40,10,0" Name="button1" VerticalAlignment="Top" Width="75">WPF</Button>

    </Grid>

</Window>

 
咱们再来一个例子:这回的需求是这样的——UI上有一个TextBox和一个Slider,要求Slider的滑块滑动时TextBox的文本显示Slider的值;当TextBox里的文本改变时,就让Slider的滑块与之同步。
 
对于一个有经验的Windows Form开发老手来说,他的思路是这样的:
  1.  在UI上拖放控件
  2.  为Slider的ValueChanged事件添加响应函数(事件处理函数),函数中将Slider的Value属性(double类型)转换成一个string类型的值并赋给TextBox的Text属性。
  3.  为TextBox的TextChanged事件添加响应函数,对TextBox的Text属性进行检验,看看它是否能解析为一个 double值(新手常常忘记这一点而导致bug)并且落在Slider的取值范围内,如果一切顺利,就把它赋给Slider的Value属性。
 
Now,你是一个WPF新手,但你可以做的比一个Windows Form老手还好!请打开Visual Studio 2008,新建一个WPF Application,然后把下面的代码copy到XAML设计器里。
 

<Window x:Class="WpfApplication1.Window1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Window1" Height="300" Width="300">

    <Grid>

        <Grid.Background>

            <LinearGradientBrush>

                <GradientStop Offset="0" Color="Blue"></GradientStop>

                <GradientStop Offset="0.5" Color="LightBlue"></GradientStop>

            </LinearGradientBrush>

        </Grid.Background>

        <TextBox Height="23" Margin="10,10,10,0" Name="textBox1" VerticalAlignment="Top" Text="{Binding ElementName=slider1, Path=Value, UpdateSourceTrigger=PropertyChanged}" />

        <Slider Height="21" Margin="10,40,10,0" Name="slider1" VerticalAlignment="Top" Maximum="100" />

    </Grid>

</Window>

   

看你,你也可以一句C#代码都不写就完成漂亮的程序!
 
 
 
我猜已经有同学开始“晕代码”了。完全没有必要!这些代码80%都是VS自动生成的,而且它们的结构的非常简单——箱子里装着一个口袋,口袋里装着两个核桃。上面这段程序最重要的一句就是:Text="{Binding ElementName=slider1, Path=Value, UpdateSourceTrigger=PropertyChanged}",即可以说它是WPF最精华的部分,也可以说它是与Windows Form开发相比变化最大的地方,它就是——Data Binding(数据关联)。这两个月来,我几乎天天与这个东西打交道。后面的文章中,我们将仔细学习如何使用它。
 
TO BE CONTINUE...
 
 
 

深入浅出WPF2——解剖最简单的GUI程序

小序:

从这篇文章开始,我们进行XAML语言的上手学习。说实话,XAML这种语言一点也不难。如果把XML看成是父类,那么XAML就是XML的一个派生类了,所以XML的概念在XAML中是通用的。What?你不了解XML?没关系,反正我们是从头开始!

正文:

你还能想起学C/C++的时候写的第一个程序吗?呵呵,一定是“Hello World”吧!今天我们来解析一个“Hello WPF”。准备好了吗?Let's go

准备知识

使用VS2008新建一个WPF Application,你立刻就会得到一个看上去是的窗体。窗体这个东西,在Windows Form程序里叫“Form”,在WPF里叫Window”——喔,Win32 API里也叫Window!是的,你说对了,WPF在某种程度上是向Win32 API返璞归真

为什么说它看上去是空的呢?实际上,这个Window的内部有一个叫<Grid>元素(Element,只是这个元素是看不见的,它就像信纸上的暗格一样。

针对XAML文件,是可以进行所见即所得的可视化设计的。你在XAML代码上做的修改,只要是合乎语法的,那么在设计器里就会立刻反映出来(有时候需要刷新一下)。如果你发现设计器里显示不出来了,那一定是XAML语句出了问题,最好想办法修正它。不然的话,在设计器里都看不到效果、只能运行起来看,这还算什么可视化编程呢?要XAML还有什么意义呢?

在我们正式剖析代码之前,让我们牢记两件事:

1.     这个世界是一个组合的世界——汽车是由一个车身和四个轮子组合成的;飞机是由机翅和机身组合成的。这些组成部分,我们称之为元素(Element

2.     XAML文件里,每写一个元素就相当于定义了一个元素所对应的.NET Framework类的实例。

有必要强调一点:如果一个实体是由一些(同类或者不同类的)子对象组合成的,我们就称这个实体为父元素、称这些子对象为子元素,因为父元素包含着子元素,所以常把父元素称为包含元素、把子元素称为被包含元素或父元素的内容”——我们需要注意,被包含元素并不等同于包含元素的属性(property),被包含元素只是包含元素的一个部分 初听这句话,肯定是一头雾水,OK,让我举个两个例子。比如有一个班级,这个班由56个学生、1个老师、60张桌子、70把椅子组成,那么这些学生、老师、桌子和椅子,只是这个班级的一些组成部分;而这个班级的人数、班级隶属的年级、班级的编号是这个班级的属性。再比如我有一个Window,这个Window里有1Grid,这个Grid里又包含着3TextBox2Button,那么这1Grid就是这个Window的子元素,3TextBox2Button又是Grid的子元素;而WindowNameIcon、尺寸乃至Resources都是这个Window的属性。

你可能会问,这个道理这么简单,有什么好强调的呀?

原因是这样的:对于C#的类而言,属性(property)肯定是一个对象(比如WindowName属性,它就是一个String类型的对象),这个对象也是类实例的一个组成部分;而在对这个类进行扩展的时候(对这个类进行派生),我们新添加进来的元素(比如3TextBox2Button)也是类实例的组成部分。OK,大家看到了,从现实世界抽象到编程世界来之后,它们的区别就不那么鲜明了。为了再让它们的区别鲜明起来,请大家记住两句话:

  • 属性对象(元素)是父元素所固有的,子元素则可由设计人员来进行增减
  • 属性对象(元素)是隶属于父类的(从父类继承而来),子元素是在设计派生类时新添加进来的

之所以在剖析代码之前讲述这些东西,是因为XAML是一种XML语言,它的语法完全是元素嵌套组合式的,而属性和子元素也都是类实例的组合体,如果不先分清楚,读代码的时候一定会感觉混乱。

 在了解了这些内容之后,我们就可以放心地读代码了。

剖析代码

 请新建一个名为HelloWPFWPF Application项目。在XAML语言编辑器里,你会看到和下面一样的代码。

<Window x:Class="HelloWPF.Window1"
    xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
    Title
="Window1" Height="300" Width="300">
    
<Grid>
        
    
</Grid>
</Window>

 让我们一个词一个词地分析这段代码。

就像我们遇到复杂长句时先要分析它的主干一样——让我们暂时抛开花花绿绿的代码,看看这段程序的主干是什么。喔~~~这段程序的主干是如此的简单!就是一个<Window>元素里包含着一个 <Grid>元素。

<Window>
    
<Grid>
        
    
</Grid>
</Window>

  一个句子的主干找出来之后,句子的大意也就明白了。我们已经得到这段程序的主干了,那这段程序说的是什么呢?前面我叮嘱大家一定要记住两件事件。其中一件就是见到元素就相当于创建实例。我想你一定会说:这段程序就是在定义一个Window类的实例,这个实例的一个组成部分是一个Grid类的实例。

呵呵,对于这个答案,既可以说它是对的,也可以说它是错的,为什么呢?

请注意,Window元素的一个attributex:Class="HelloWPF.Window1",这个Class就是在告诉我们嘿!本XAML文件实际上是这个类的UI部分哦!。本例中,类名就是等号后面的“HelloWPF.Window1”,也就是说,是HelloWPF名称空间中的Window1这个类。在项目浏览器中找到与这个XAML文件配套的C#文件(XAML文件名.cs),果然能找到这个类。

    public partial class Window1 Window
    {
        
public Window1()
        {
            InitializeComponent();
        }
    }

从这个角度来看,上面的答案就是错的了——因为这段代码是在定义一个Window1的实例会是什么样子。

那为什么又可以说它的对的呢?显然,Window1Window类的派生类,根据多态的原理,你说Window1“是一个”Window并没有错——就像你说鸭子是一只鸟一样正确。在派生过程中,我们使用<Grid>标签为它添加了一个Grid类型的UI成员——派生吗,一定是要做些扩展的。

看到这儿,我想你已经猜到了,XAML文件就是用来定义Window1这个类的UI部分(一旦这个类创建了实例,那这个实例的UI将与XAML代码的描述相一致)。微软通过XAML语言把UI设计完全暴露给了我们,让设计师可以像设计网页一样来设计桌面程序的界面。至于这个类的逻辑部分,还是用传统的C#语言来实现。这样,设计人员和开发人员就能各司其职、协同工作了。

一个类能够掰成两半来写,这要归功于partial这个关键字,使用这个关键字,可以把一个类的代码分散在多处来实现。可问题又来了——XAML代码怎么和C#代码对接啊?呵呵,这个还真不用咱们操心,微软的XAML解析器本着进村悄悄地,开枪地不要原则,在背后把这件事完成了。因为XAML代码中没有逻辑,所以,解析XAML的大部分工作就是按照元素标签的描述把对象创建出来——比如,解析器见到有<Grid>标签出现,就会生成与C#代码new Grid()等价的代码。

喘口气儿……
让我们继续。

XAML名称空间

如果你问一个初学XAML的人(碰巧他还没有XML编程经验):最让他迷惑的是什么?我想他会告诉是:就是那个x老实讲,我就是他们中的一员,初学的时候我也很痛恨那个x。一会儿是“:x”,一会儿是“x:”……这个x到底是什么呢?

其实非常简单——这个x是一个名称空间、一个使用XML语法声明的名称空间。只是XML语言声明名称空间的时候语法比较怪而已。下面,让我一一为你解释。

首先,如果你使用C#,那么你对这几句代码一定不陌生:



这是对.NET Framework类库中名称空间的引用。一旦引用了这些名称空间,在使用这些名称空间中的类时就不并在再类名前加上长长的前缀了。

请大家考虑这样一种情况:有两个很长的名称空间,我需要使用它们中的类,但不巧的是这两个名称空间里的类又有很多是重名的……怎么办呢?呵呵,我们可以使用名称空间的别名来解决这个问题:

using Software Microsoft.Google.Adobe.RedHat.CA;
using Hardware IBM.Sun.RedHat.Dell.Lenovo.HP.Oracle;

 

这样,即解决了输入字符过多的问题,又解决了类名冲突的问题:

Software.Company c1 new Software.Company();
Hardware.
Company c2 new Hardware.Company();

 

XAML名称空间跟C#的名称空间别名类似,但不完全一样。先让我们看那个xx其实就是一个简写的名称空间啦!xmlns就是XML Namespace的简写,意思是要声明一个名称空间。

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

这句话的意思就是:声明一个名为x的名称空间(xmlns与名称空间的名字间用冒号隔开)。后面为什么要跟一个网址呢?呵呵,我们都被骗了——那根本不是一个网址,不信你用IE试试。其实,它就是一个普通的字符串,你尽可以把它当成“Microsoft.WinFX.XAML”来理解。但值得注意的一点是:这个字符串不只代表着一个名称空间,而是代表了一组名称空间,这组名称空间合称“XAML语言空间”——因此,它的名字是x。换句话说,这个x相当于一下子引用了好几个名称空间进来,这几个名称空间在.NET Framework里都能查到,包含这些名称空间里的类都是与XAML语言的语法、特性、功能有关的。

XAML中,想使用某个名称空间里的类就要使用名称空间+冒号+类名的格式,所以:
x:Class的意思是使用x名称空间里名为Class的类。类似地,以后我们还会看到x:Staticx:Typex:XData等等,这都是在使用x这个名称空间里的类。

与声明x名称空间类似,这儿还有一句:
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

这回的网址与前面的不一样,最后一个词是“presentation”,顾名思义,这回引用进来的一组名称空间一定是与显示相关的。说对了!比如System.Window.Control这个.NET Framework的名称空间就包含在里面,这个名称空间里几乎包含了所有WPFUI元素(WPF里,我们称控件为UI元素)。 

你可能会问:这不是在声明名称空间吗!名字哪儿去了?
问的非常好!当xmlns后面没有跟随名称空间的名字时,就相当于省去了名称空间的名字,当使用这个名称空间中的类时就无需再加前缀(根本没前缀可加,怎么加?)。换句话说,当一个类名前面没有前缀时,默认就是此名称空间里的类。因此,它称为默认名称空间。这个用法跟using System差不多。BTW:默认名称空间只能有一个。

大家可以动手试试这样做,把xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"改成xmlns:n="http://schemas.microsoft.com/winfx/2006/xaml/presentation", 这时候程序就编译不过去了。当你把后面的<Grid>元素改成<n:Grid></n:Grid>后,就又可以通过编译了。

 最后,Title="Window1" Height="300" Width="300"的意思是设置Window1类(也可以说是Window类)的几个实例属性。这种语法称为使用标签的attribute设置对象的property”,碰巧,attributeproperty这两个词都被译为了属性,所以这句话就没法翻译了。除了使用attribute设置对象property的语法外,XAML还支持使用子元素方式设置元素属性的语法。下面这段代码与原代码是等价的:

<Window x:Class="HelloWPF.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Window.Title>Window1</Window.Title>
    <Window.Height>300</Window.Height>
    <Window.Width>300</Window.Width>
    <Grid>
        
    
</Grid>
</Window> 

大家注意啦!<Window.Title><Window.Height><Window.Width>叫做属性元素,表示它虽然是一个子元素,但它是父元素的一个属性;而<Grid>则是一个普通元素,而非<Window>元素的属性——它们虽然都是<Window>的组成元素,但不是一个圈子里的(请跳转到上面,看看准备知识)。总有初学者问我:反正Title也是Window的一个组成部分,能不能写成<Title>Window1</Title>啊?幽默点讲,XAML解析器没那么聪明;地道的说法是,从物理上讲,并没有<Title>这个UI元素;从XAML语法上讲,这样会造成语义上的含混、远不及<Window.Title>来得清晰。

啰嗦一句:当对象的property用一个简单的string就能描述清楚时,完全没必要使用子元素式语法小题大作。当对象的属性是一个复杂的对象时(你想用attribute式语法都办不到),再使用子元素式语法。

到此,一个最简单的WPF程序(的XAML部分)就算分析完了。本文成于仓促,之间有不少不严谨的地方,我会慢慢修改。大家有什么好的建议,请在文后盖楼。

~~~看来今天是Hello不了WPF鸟,以后再说吧~~~    摘自、整理自刘铁猛前辈Blog里的东西

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值