WPF 基础到企业应用系列3WPF开发漫谈

1.开篇前言

首先很高兴这个系列能得到大家的关注和支持,基于对大家负责和对自己负责的态度,我会不断努力写好这个系列,分享自己的微薄技术和经验,希望在帮助别人的同时也不断提升自己。由于这篇文章稍多,所以读者花的时间长了一些,也希望大家能够见谅,这个系列以后会每周发三到四篇左右(主要是写一篇差不多要花几晚上,感觉思维比较发散),除了讲WPF技术本身之外,也会讲一些项目具体开发,所以敬请关注。在前两次的文章中我们对WPF有了一个比较全面的认识,那么在本篇文章当中,除了讲一些理论知识外,我们会从实际的开发中进行讲解,用理论和代码的形式来诠释WPF的简单开发过程。

2.本文提纲

· 1.开篇前言

· 2.本文提纲

· 3.WPF开发基础

· 4.Expression系列工具简单介绍

· 5.其他工具介绍

· 6.WPF和WinForm案例

. 7.漫谈WPF开发

· 8.本文总结

. 9.系列进度

3.WPF开发基础

本系列文章默认情况下,开发环境为Windows XP+SP3英文版和Visual Studio 2008+SP1英文版。要使用Windows 7  Professional和Visual Studio 2010开发环境的时候会附加说明。在搭建好开发环境之后,打开VS2008,选择创建项目(Create Project),出现如下图所示的选择项目模板的对话框:

在项目模板选择对话框中选择WPF Application,修改项目名称(Name)(已经截图完毕,所以没能改名,望见谅),和存储位置(Location),点击 确定 (OK)按钮,便成功创建了一个WPF应用程序,模板中文件层次结构如下图所示(在References里面自动引入了图一中的PresentationCore、PresentationFramework、WindowsBase三大核心程序集):

图二

在App.xaml中,指定项目运行时启动的是窗体:Window1,还可以定义我们需要的系统资源以及引入程序集等,详细看下图介绍:

在Window1.xaml中设计窗体的外观,首先,我们将窗体的Title更改为:XAMLWithScript,然后设置窗体的其他属性和事件 。完成了这些设置以后,我们就可以对窗体添加内容了,本实例对窗体添加了一个Button,然后对Button进行了一些简单的设置,详细如下图所示:

上图没有对一些概念讲全,所以下面这幅图用另外一个窗体对某些概念进行了补充,由于我把很多概念都画到了图里面,所以在此就不做过多解释,详细如下:

由于每个概念都比较细且多的缘故,所以这里只是对一些基本的概念和元素进行了展示,后续文章会做一一介绍,也欢迎和大家一起讨论!

4.Expression工具的使用

由于自己主攻方向不在这个方面,所以对这些工具也只是会使用而已,会用Expression做一些基本的效果和应用,但更多时候都是在visual studio里面手写代码,不过有的时候为了配合美工进行代码集成,也会接触这些工具。

在 Expression Design 中打开作品文件。(这个作品有可能是你用其他工具创建的,也可以是你用Expression Design 设计的,但个人认为它还是没有Photoshop/CorelDraw/Fireworks等工具好用。)
    如果要导出切片,请从“工具箱”中选择“切分”工具,围绕所要导出的作品区域绘制一个矩形,然后在“属性”面板中的“编辑切片”下,设置切片的属性(如“Name”)。
单击“文件”菜单上的“导出”。此时,将显示“导出”对话框。
在“要导出的项”下,选择以下选项之一:

“整个文档”   导出文档中的所有作品。“选定对象”   只导出那些在美工板上选定的项目。 “切片”   只导出生成的切片。您可以根据情况选择更改所显示的每个切片的属性。

接下来设置“格式”,请选择以下任一选项:

“XAML Silverlight 画布”   导出单个 XAML 文件,其中包含表示为画布版式面板中的对象的所有作品。您可以在 Expression Blend 3中将此 XAML 文件导入到 Microsoft Silverlight 项目内,以用作独立的文档(启动的 XAML 文件或以编程方式加载的 XAML 文件),或将对象复制并粘贴到另一个 XAML 文档中。 “XAML WPF 图形画笔”   导出一个资源字典,其中包含表示为图形画笔资源的所有作品。您可以在 Expression Blend 3 中将此 XAML 文件导入到 Windows Presentation Foundation (WPF) 项目内,然后将这些资源应用于项目中的对象的画笔属性。 “XAML WPF 画布”   导出单个 XAML 文件,其中包含表示为画布版式面板中的对象的所有作品。您可以在 Expression Blend 3 中将此 XAML 文件导入到 Windows Presentation Foundation 项目内,以用作独立的文档(启动的 XAML 文件或以编程方式加载的 XAML 文件),或将对象复制并粘贴到另一个 XAML 文档中。您还可以在 Expression Blend 3 的“设计”视图中打开该文件,右键单击任意一个或多个对象,然后通过选择“工具”菜单上的选项,利用这些对象来创建按钮或用户控件。

在对话框底部的“位置”框旁边,键入导出文件所在的文件夹的路径(我们这里就保存在D盘)。还可以设置下列选项:

如果决定导出“整个文档”或“选定对象”,还需要输入文件的名称。如果决定导出“切片”,则可以根据情况选择一个版式面板以包含所有对象。

单击“全部导出”以导出文件。

在 Expression Blend 3 中打开的项目内,单击“项目”菜单上的“添加现有项”。

在“添加现有项”对话框中,浏览找到所导出的一个或多个 XAML 文件,选择这些文件,然后单击“打开”。

5.其他的一些工具

除了上面我们用到的Expression Design、Expression Blend和Visual Studio以外,我们还会用到一些其他的工具,比如一些调试工具、一些性能优化工具和XAML查看工具。

KaXaml是一个轻量级的XAML编辑器,用它之前我们一直都是用XAMLPad,但是用了KaXaml以后才发现XAMLPad是那么的不好用,并且KaXaml是开源的,在codeplex上进行了发布,感兴趣的朋友也可以下载它的源代码进行研究。

它主要的功能如下:

1,内置诸多代码片段(模版)

2,内置ColorPicker

3,xaml  scrubber : 可以帮你清理你的XAML代码

4,支持语法高亮和智能提示

其他的一些工具和资源,园子里周金根做了一些收集,我在这里也不做一一介绍了,大家可以看一下他的博客,详细地址:WPF - 资源收集,我觉得整理的非常的不错。

6.WPF和WinForm案例 介绍

这个例子主要展示同一个需求用WinForm和WPF分别进行实现,通过这个例子,我们可以看到两者之间的区别和联系,同时也可以对我们的项目选型带来一定的参考作用(原型来自于Josh Smith的一篇文章,个人觉得讲得非常不错,所以对原有例子进行了改造,进而有了这个案例)。

当然作为一项新技术,WPF带来了很多功能,但在使用这些功能的同时也会带来很多缺点,这是不可避免的,正所谓”有利必有弊“吧!所以我们这个例子并不是讲WPF有如何如何的好,怎样用WPF代替WinForm,而是从两者实现同一个需求进行简单的对比。

这个例子是用Visual Studio 2008编写的,所以大家可以下载下来进行查看.

特别声明

这个程序并不是要展现声明优秀的架构也不是为了宣扬WPF的种种好处,所以没有采用当前比较热门的MVP、MVVM模式进行开发,同时项目当中你可以看到很随意的代码,没有对IOC、AOP以及设计模式进行应用,这也是考虑到具体需求和例子简单的原因,况且这里也没有必要,我们在做项目的时候也要时刻注意什么时候用什么开发框架、开发模式以及项目整体架构。

程序概览

这个例子非常简单,需求就是展示三大社区的基本信息,同时你可以在输入框对其进行修改,当焦点切换的时候,你就会看到它会自动进行修改,你把鼠标放在图片上面会提示社区的ID等等。我在这里没有用复杂的逻辑和高深的架构,只是想通过这个例子展示WinForm的WPF的差异和联系,所以在程序处理上可能会有很多漏洞,比如没有对输入进行验证,你可以输入空格和任意字符等。

下面是WinForms版本的截图:

下面是WPF版本的截图:

如果你编辑了某个社区的中文名称或者英文名称,然后把焦点移到另外一个地方,这些更改就会通过右上角的全名体现出来,因为他们都是通过绑定到公用字段来实现这些操作的。

整个项目结构如下图所示:

整个项目一共就三个工程,第一个工程BusinessObjects 是WpfApp和WinFormsApp公用的业务类库,WinFormsApp是用WinForm实现的版本,WpfApp是用WPF实现的版本。那么我们下面就简单分别进行一些介绍:

公用代码部分(BusinessObjects)

这两个应用程序都是使用的BusinessObjects作为逻辑类库,BusinessObjects中的Company对UI所使用的数据进行了Mock。所以他们在需求方面都是一样的,由于比较简单,所以请看下面代码:

Collapse

using System;

using System.ComponentModel;

using System.IO;

using System.Reflection;

namespace BusinessObjects

{

public class Company : INotifyPropertyChanged

{

#region Creation

public static Company[] GetCompanys()

{

// In a real app this would probably call into a data access layer to get records from a database.

return new Company[]

{

new Company(1, "博客园", "CNBlogs", GetPictureFile(1), new DateTime(2004, 1, 12)),

new Company(2, "51CTO", "51CTO", GetPictureFile(2), new DateTime(2005, 3, 1)),

new Company(3, "CSDN", "CSDN", GetPictureFile(3), new DateTime(2000, 1, 20)),

};

}

private static string GetPictureFile(int CompanyID)

{

string fileName = String.Format("emp{0}.jpg", CompanyID);

string folder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

folder = Path.Combine(folder, "Images");

return Path.Combine(folder, fileName);

}

private Company(int id, string chineseName, string EnglishName, string pictureFile, DateTime startDate)

{

this.ID = id;

this.chineseName = chineseName;

this.EnglishName = EnglishName;

this.PictureFile = pictureFile;

this.StartDate = startDate;

}

#endregion // Creation

#region Properties

public int ID { get; private set; }

string _chineseName;

public string chineseName

{

get { return _chineseName; }

set

{

if (value == _chineseName)

return;

_chineseName = value;

this.OnPropertyChanged("chineseName");

this.OnPropertyChanged("FullName");

}

}

string _EnglishName;

public string EnglishName

{

get { return _EnglishName; }

set

{

if (value == _EnglishName)

return;

_EnglishName = value;

this.OnPropertyChanged("EnglishName");

this.OnPropertyChanged("FullName");

}

}

public string FullName

{

get { return String.Format("{0}, {1}", this.EnglishName, this.chineseName); }

}

public string PictureFile { get; private set; }

public DateTime StartDate { get; private set; }

#endregion // Properties

#region INotifyPropertyChanged Members

public event PropertyChangedEventHandler PropertyChanged;

protected virtual void OnPropertyChanged(string propertyName)

{

PropertyChangedEventHandler handler = this.PropertyChanged;

if (handler != null)

handler(this, new PropertyChangedEventArgs(propertyName));

}

#endregion

}

}

上面这段代码没有什么不寻常的地方,大家写WinForm和Asp.Net也会写这样的逻辑类,只是要注意Company 实现了INotifyPropertyChanged 接口,大家看到这个接口只有一个OnPropertyChanged的方法,这个方法就是我们要说的属性变更通知方法,就是说当一个属性改变了,我们需要做些什么来响应这些改变。

WinForms实现介绍

WinForms版本就包含一个Form 和一个展示社区信息的custom UserControl, 这个Form 包含了一个FlowLayoutPanel控件, 它主要的作用就是用来承载每个社区的实例. 那么代码就如下所示:

Collapse

public partial class Form1 : Form

{

public Form1()

{

InitializeComponent();

// Create and initialize a usercontrol for each Company.

foreach(Company com in Company.GetCompanys())

{

CompanyControl comCtrl = new CompanyControl();

comCtrl.Company = com;

this.flowLayoutPanel.Controls.Add(comCtrl);

}

}

}

CompanyControl是我们创建的一个UserControl,由于每个CompanyControl都要显示一个Company对象的属性值,我在这里使用了BindingSource控件来进行绑定,这样做也是为了和WPF更接近考虑(增强对比性,呵呵)。具体如下截图:

如上图所示,我们用了BindingSource来获取数据,但有一个属性除外,那就是Company ID,请看下面代码:

Collapse

namespace WinFormsApp

{

///

/// A WinForms control that displays an Company object.

///

public partial class CompanyControl : UserControl

{

public CompanyControl()

{

InitializeComponent();

// Convert the picture file path to a Bitmap.

Binding binding = this.CompanyPicture.DataBindings[0];

binding.Format += this.ConvertFilePathToBitmap;

}

void ConvertFilePathToBitmap(object sender, ConvertEventArgs e)

{

e.Value = Bitmap.FromFile(e.Value as string);

}

public Company Company

{

get { return this.CompanyBindingSource.DataSource as Company; }

set

{

this.CompanyBindingSource.DataSource = value;

// The Company's picture shows a tooltip of their ID.

if (value != null)

{

string msg = "Company ID: " + value.ID;

this.toolTip.SetToolTip(this.CompanyPicture, msg);

}

}

}

}

}

这里有几点需要注意.在绑定的时候,我们对PictureFile 字段进行了转换,这个是必须做的. 如果不那样做, 这个图片会绑定失败,因为在绑定的时候它不能自动把string类型直接转化为Image类型.

现在我们已经把Company绑定到了我们的控件上, 这里我需要给PictureBox一个tooltip的效果. 这个tooltip将显示 Company ID, 前缀显示为 "Company ID:". 现在这个是在代码里面写的,没有在窗体中发现有WPF ToolTip等类似的工具,不知道大家用到过没有?

总的来说, 这是一个很简单的例子,我们的大部分功能也是用代码没有写代码,是通过visual designer进行实现的.然后通过一部分代码把它衔接起来, 我们看到Windows Forms是一个非常快速和实用的开发平台.

WPF实现介绍

WPF版本我这里就做得很简单了,由于开发WPF程序提供了很多模板和工具,所以我这里基本没写什么代码,全部的代码都是通过XAML实现,并且大部分都是自动生成的,只是我们要根据项目具体情况做一些修改就行。

这个WPF项目同样有一个Window 和一个custom UserControl, 和 WinForms 版本基本一样. 只是WinForms中用 FlowLayoutPanel来承载EmployeeControls 控件, 而WPF 用的是ItemsControl 来承载这个用户控件.更加可喜的是,WPF通过模板来进行定制,所以我们就不需要像WinForms那样写循环加载控件的代码,下面就是WPF用XAML实现的窗体代码:

Collapse

<Window

x:Class="WpfApp.Window1"

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

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

xmlns:local="clr-namespace:WpfApp"

xmlns:model="clr-namespace:BusinessObjects;assembly=BusinessObjects"

Title="WPF App" Height="558" Width="581"

WindowStartupLocation="CenterScreen"

>

<Window.DataContext>

<ObjectDataProvider

ObjectType="{x:Type model:Company}"

MethodName="GetCompanys"

/>

Window.DataContext>

<Grid Width="555">

<Label

Name="label1"

HorizontalContentAlignment="Center" VerticalAlignment="Top"

FontSize="20" FontWeight="Bold"

Height="36.6" Margin="0,16,0,0"

>

.NET 中文社区大比拼Label>

<ItemsControl

ItemsSource="{Binding}"

HorizontalContentAlignment="Center"

Margin="46,59,25,0"

Focusable="False"

>

<ItemsControl.ItemTemplate>

<DataTemplate>

<local:CompanyControl />

DataTemplate>

ItemsControl.ItemTemplate>

ItemsControl>

Grid>

Window>

在如下的XAML代码中,这里有几点需要注意,。Window的DataContext赋予了一个ObjectDataProvider的对象,而ObjectDataProvider又会调用GetEmployees这个方法。所以一旦把DataContext设置到Company 对象,并且把ItemsControl的ItemsSource设置为“{Binding}” 就意味着该控件里面会自动显示Company 对象的所有数据。

这里我们并不需要像WinForm一样用循环的方式创建CompanyControl的实例。这是因为ItemsControl中的ItemTemplate属性设置为了一个DataTemplate,同时ItemsControl中的ItemsSource绑定到了Company 的对象数组,那么ItemTemplate就会知道如何创建一个CompanyControl,所以大家看到这里写的代码就相对变少了,这也是XAML的一个优点之一。

该CompanyControl的后台CS文件也是空的(除了必须的InitializeComponent),所以它不像的WinForms应用程序那么累赘,界面和逻辑紧密的耦合在了一起。下面就是CompanyControl的XAML代码, 这个代码相对来说就比较简单了。

Collapse

<UserControl x:Class="WpfApp.CompanyControl"

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

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

Height="137" Width="481">

<Border

BorderBrush="Black"

BorderThickness="1"

Margin="2"

SnapsToDevicePixels="True" Width="469">

<Grid Height="129" Width="451">

<Image Source="{Binding PictureFile}"

Margin="10" Name="image1" Stretch="Fill"

Width="150" Height="80" HorizontalAlignment="Left" >

<Image.ToolTip>

<TextBlock>

<Run TextBlock.FontWeight="Bold">Company ID:Run>

<TextBlock Margin="4,0,0,0" Text="{Binding ID}" />

TextBlock>

Image.ToolTip>

Image>

<Label

Content="{Binding FullName}"

时间: 2024-09-19 20:37:23

WPF 基础到企业应用系列3WPF开发漫谈的相关文章

一起谈.NET技术,WPF 基础到企业应用系列3——WPF开发漫谈

1.开篇前言      首先很高兴这个系列能得到大家的关注和支持,基于对大家负责和对自己负责的态度,我会不断努力写好这个系列,分享自己的微薄技术和经验,希望在帮助别人的同时也不断提升自己.由于这篇文章稍多,所以读者花的时间长了一些,也希望大家能够见谅,这个系列以后会每周发三到四篇左右(主要是写一篇差不多要花几晚上,感觉思维比较发散),除了讲WPF技术本身之外,也会讲一些项目具体开发,所以敬请关注.在前两次的文章中我们对WPF有了一个比较全面的认识,那么在本篇文章当中,除了讲一些理论知识外,我们会

WPF基础到企业应用系列1——开篇有益

1.开篇前言 关于本人--圣殿骑士刚入住博客园和51CTO写技术博客,目前主要在一家外资企业从事项目管理.技术架构及企业技术培训工作.由于工作和项目需要,所以对一些技术进行了较为深入的研究,之前在整个公司做过一些技术专场的培训,由于每次时间较短且人员较多的关系,没能讲得很透彻,所以挺对不住那些同事的.现在在园子里开一个博客,希望能把所学的微薄知识书写出来,以供大家参考.近期将针对这些培训专场推出"OO到设计模式"."WCF基础到企业应用"."WPF基础到企

一起谈.NET技术,WPF 基础到企业应用系列4——WPF千年轮回

1.开篇前言      首先很高兴这个系列能得到大家的关注和支持,基于对大家负责和对自己负责的态度,我会不断努力写好这个系列,分享自己的微薄技术和经验,希望在帮助别人的同时也不断提升自己.由于这篇文章很多(现已拆分成2篇,今天这篇只是其中之一),一共花了几个个晚上的休息时间才完成,所以读者花的时间长了一些,也希望大家能够见谅,这个系列以后会每周发三到四篇左右(主要是写一篇差不多要花几晚上,感觉思维比较发散),除了讲WPF技术本身之外,也会讲一些项目具体开发,所以敬请关注.     本篇文章取名为

一起谈.NET技术,WPF 基础到企业应用系列2——WPF前世今生

1.开篇前言      很多时候了解一项新技术的历史和趋势往往比这项技术的本身价值还要重要.WPF作为一项新技术(已经三年多了,或者应该叫老技术了),我们都有必要了解它的来龙去脉,尤其是公司的CTO.技术总监.架构师等决策层,因为他们对技术的选型及应用具有决定权.对于开发者来说,了解自己正在从事的这个技术的前世今生,有助于我们更好的认识技术本身的价值,也可以避免我们少走一些弯路(圣殿骑士 就走过很多弯路,所以对此比较感慨).从IT技术发展的这些年可以看出,技术对于各大公司只是竞争的一种手段,而对

一起谈.NET技术,WPF 基础到企业应用系列1——开篇有益

1.开篇前言 关于本人--圣殿骑士刚入住博客园和51CTO写技术博客,目前主要在一家外资企业从事项目管理.技术架构及企业技术培训工作.由于工作和项目需要,所以对一些技术进行了较为深入的研究,之前在整个公司做过一些技术专场的培训,由于每次时间较短且人员较多的关系,没能讲得很透彻,所以挺对不住那些同事的.现在在园子里开一个博客,希望能把所学的微薄知识书写出来,以供大家参考.近期将针对这些培训专场推出"OO到设计模式"."WCF基础到企业应用"."WPF基础到企

WPF 基础到企业应用系列1开篇有益

1.开篇前言 关于本人--圣殿骑士刚入住博客园和51CTO写技术博客,目前主要在一家外资企业从事项目管理.技术架构及企业技术培训工作.由于工作和项目需要,所以对一些技术进行了较为深入的研究,之前在整个公司做过一些技术专场的培训,由于每次时间较短且人员较多的关系,没能讲得很透彻,所以挺对不住那些同事的.现在在园子里开一个博客,希望能把所学的微薄知识书写出来,以供大家参考.近期将针对这些培训专场推出"OO到设计模式"."WCF基础到企业应用"."WPF基础到企

WPF 基础到企业应用系列2WPF前世今生

1.开篇前言 很多时候了解一项新技术的历史和趋势往往比这项技术的本身价值还要重要.WPF作为一项新技术(已经三年多了,或者应该叫老技术了),我们都有必要了解它的来龙去脉,尤其是公司的CTO.技术总监.架构师等决策层,因为他们对技术的选型及应用具有决定权.对于开发者来说,了解自己正在从事的这个技术的前世今生,有助于我们更好的认识技术本身的价值,也可以避免我们少走一些弯路(圣殿骑士 就走过很多弯路,所以对此比较感慨).从IT技术发展的这些年可以看出,技术对于各大公司只是竞争的一种手段,而对于大多数程

WPF基础到企业应用系列3——WPF开发漫谈

1.开篇前言 首先很高兴这个系列能得到大家的关注和支持,基于对大家负责和对自己负责的态度,我会不断努力写好这个系列,分享自己的微薄技术和经验,希望在帮助别人的同时也不断提升自己.由于这篇文章稍多,所以读者花的时间长了一些,也希望大家能够见谅,这个系列以后会每周发三到四篇左右(主要是写一篇差不多要花几晚上,感觉思维比较发散),除了讲WPF技术本身之外,也会讲一些项目具体开发,所以敬请关注.在前两次的文章中我们对WPF有了一个比较全面的认识,那么在本篇文章当中,除了讲一些理论知识外,我们会从实际的开

WPF基础到企业应用系列5——WPF千年轮回 续前缘

一,摘要 这篇课程主要是对上几次课程的回顾和简单深化,所以没有讲什么比较新的概念,不过掌握好了这篇,对后面的很多文章都有帮助,同时这一篇文章做Demo.构思.研究等也花费了不少时间,所以希望对大家有所帮助. 二,本文提纲 · 1.摘要 · 2.本文提纲 · 3.前篇回顾 · 4.Xaml基础 · 5.脱离VS工具CSC编译WPF · 6.XamlReader与XamlWriter · 7.本文总结 . 8.系列进度 三,前篇回顾 在我们日常的开发中,软件企业的开发人员一般会有两种类型的工作: 1