《C#高级编程(第8版)》之用C# 2012和.NET 4.5编写Windows 8样式应用程序技巧

 

本文介绍Windows 8应用程序的设计原则和WPF不支持的一些特殊XAML功能,演示操作Windows 8应用程序的几个方面,例如响应布局的变化,使用Windows Runtime存储API和文件选择器读写文件,使用协议与其他应用程序通信等。《C#高级编程(第8版)》之用C# 2012和.NET 4.5编写Windows 8样式应用程序技巧_第1张图片
 
一  Windows 8的现代UI设计
      Windows 8应用程序中第一个引人注目的地方是,它们看起来与桌面应用程序不同。UI设计着重强调了一点,就是用户在使用应用程序时应感到愉悦和享受。Windows 8应用程序如此注重设计,源自一些旧有的理念。其中一个理念是瑞士风格的图形设计,这是20世纪50年代提出的,强调干净(不凌乱)和易于理解。例如,飞机场和火车站的信号就基于这个概念,用户可以尽快处理信息。
     德国著名的包浩斯(Bauhaus)学校是现代UI设计的另一个发源地,它在1919年—1933年间极有影响力。这所学院的目标是将艺术、工艺和技术结合起来,根据功能而不是装饰来设计—— 没有任何多余的修饰。
第三个基础是电影艺术定义的动作。动画是给应用程序带来生气的重要工具,Windows 8框架提供了丰富的动画功能,使用户在传递信息时具有身历其境的体验,把使用应用程序变成一种享受。
1.1  内容,不是chrome设计
      设计Windows 8应用程序的指导原则是注重内容,这意味着,在任何时刻,都只向用户显示他们需要的信息,而不是用他们不需要的信息(即chrome,如菜单、工具栏等)。用户打开Internet Explorer时,内容就会占满整个视图。菜单是隐藏的,除非用户显式激活了它。
例如,网页占满了整个屏幕,用户可以快速搜寻需要的内容,而没有各种菜单和工具栏的打扰。图1显示了一个天气应用程序的主视图。注意大图形更便于用户迅速把注意力集中在需要的信息上。

  《C#高级编程(第8版)》之用C# 2012和.NET 4.5编写Windows 8样式应用程序技巧_第2张图片
图1
      当然,在应用程序内,用户也可以改变设置,使用命令。要修改设置,可以使用新的Charms工具栏(Charms bar)。要激活Charms工具栏,用户可以单击屏幕的右边界,调用改变应用程序设置所需的控件。
命令放在屏幕顶部或底部的app工具栏中,要激活这些命令,用户可以使用类似的方式,即单击屏幕的顶部或底部,打开它们。图2显示了Windows Store命令栏。在该例中,命令位于屏幕顶部。
  《C#高级编程(第8版)》之用C# 2012和.NET 4.5编写Windows 8样式应用程序技巧_第3张图片
图2
1.2  快速流畅
      快速流畅是Windows 8应用程序的另一个重要原则。在传统的用户界面中使用鼠标时,用户习惯于有一点儿延迟。同样,单击按钮或在屏幕上移动某些对象时,也习惯于有一点儿延迟。这种延迟在触摸模式下是不可接受的。如果在触摸后屏幕没有立即产生什么反映,或者UI没有响应,用户的体验就会很差。
新的Windows Runtime规定,如果一个方法的执行时间超过50ms,就只能异步执行。在.NET框架中,许多API调用既有同步版本,又有异步版本。
      因为同步编程比异步编程更容易创建,所以一般使用API的同步版本。使用C# 5.0中新的异步功能,以及async和await关键字,异步API调用也非常容易使用。第13章介绍了这些新关键字的所有细节。除了使用异步API之外,还应在应用程序中为执行很长时间的任务创建异步API。
      异步编程仅是实现快速流畅这一原则的一部分。如前所述,Windows 8能很好地支持动画,因为它们以自然、真实的方式把用户体验联系在一起,且不会分散注意力。内置控件已经有动画,允许编写出流畅的切换效果,而不是很突然的变化。使用这些内置控件,就不需要定义自定义动画,但如果愿意,也是可以定义自定义动画的。
1.3  可读性
可读性对于任何应用程序都很重要,而Windows 8提供了完整的样式应用规则集。这些规则覆盖了用户体验的所有排版方面,包括可读的字体、颜色和字母间距。例如,Segoe UI字体应用于UI元素(按钮、日期选择器),Calibri字体用于用户读写的文本,Cambria字体用于大文本块。
二  示例应用程序的核心功能
      本节开发的Windows 8示例应用程序用于创建菜单卡。后面看到的菜单和图片都来自我妻子在维也纳市中心开的饭店http://www.kantine.at,欢迎读者光临该饭店。
在该应用程序中,饭店可以创建菜单卡,例如早餐、午餐卡和汤羹卡等。通过这个功能,应用程序使用XAML和C#获得用户的信息,以写入数据,处理菜单卡的图像,以及与应用程序相关的其他任务。
示例应用程序的创建从Windows Store类别中的Blank App (XAML)模板开始,如图3所示。
  《C#高级编程(第8版)》之用C# 2012和.NET 4.5编写Windows 8样式应用程序技巧_第4张图片
图3
2.1  文件和目录
      在根据模板创建的项目中,解决方案包含几个目录和一些文件。Assets目录包含应用程序的徽标(Logo)图像和一个闪屏。Common目录包含从模板中创建和使用的标准样式和实用工具类。在Blank App (XAML)模板中,Common目录只包含样式(文件名为StandardStyles.xaml)。在给项目添加使用项模板的其他功能时,添加特性类。项目中最重要的文件是App.xaml及其代码文件App.xaml.cs,MainPage.xaml及其代码文件MainPage.xaml.cs,以及Package.appxmanifest。XAML和代码文件非常类似于第35章中WPF的结构。
Package.appxmanifest 是一个XML文件,描述了应用程序的打包和功能。用Visual Studio打开这个文件,会打开清单设计器Manifest Designer,如图4所示。其中定义了应用程序名、徽标图像和闪屏。图像所需的像素尺寸显示在这个编辑器中。徽标需要150×150像素,如果应用程序还支持宽徽标(用户可以选择它),则宽徽标需要310×150像素。闪屏需要620×300像素。可以添加PNG或JPG文件。
应用程序的入口点是App类。在这个类中实例化了主页。除了UI的定义之外,也使用该软件包指定了功能和声明。在Capabilities选项卡,应用程序指定是否希望访问麦克风或网络摄像头等设备。在Windows Store中安装应用程序时,会告诉用户应用程序有什么需求。如果没有声明,应用程序就不能使用这些设备。在Declarations选项卡,应用程序声明了它支持的功能,例如,它是否可用于搜索系统;或者它是否提供共享目标,以允许其他应用程序为它提供一些数据。
下面给应用程序添加一些页面。
  《C#高级编程(第8版)》之用C# 2012和.NET 4.5编写Windows 8样式应用程序技巧_第5张图片
图4
2.2  应用程序数据
      对于要在UI中使用的数据,应用程序在DataModel子目录中定义了几个类型。类MenuCard(代码文件MenuCard/DataModel/MenuCard.cs)表示包含应用程序主要数据的菜单卡。这个类定义了用于显示的属性Title、Description和Image。与用于数据绑定的所有类一样,MenuCard也派生自基类BindingBase。BindingBase提供了INotifyPropertyChanged的实现代码。SetProperty方法用属性的set访问器调用,由这个基类实现,用于更改通知。这个基类现在还不存在,3.3小节会使用Visual Studio项模板来创建它:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
using Wrox.Win8.Common;

namespace Wrox.Win8.DataModel
{
public class MenuCard : BindableBase
{
private string title;
public string Titled
{
get { return title; }
set
{
SetProperty(ref title, value);
SetDirty();
}
}

private string description;
public string Description
{
get { return description; }
set
{
SetProperty(ref description, value);
SetDirty();
}
}

private ImageSource image;
public ImageSource Image
{
get { return image; }
set { SetProperty(ref image, value); }
}

private string imagePath;
public string ImagePath
{
get { return imagePath; }
set { imagePath = value; }
}

public void SetDirty()
{
IsDirty = true;
}
public void ClearDirty()
{
IsDirty = false;
}
public bool IsDirty { get; private set; }

private readonly ICollection menuItems =
new ObservableCollection();
public ICollection MenuItems
{
get { return menuItems; }
}

public void RestoreReferences()
{
foreach (var menuItem in MenuItems)
{
menuItem.MenuCard = this;
}
}

public override string ToString()
{
return Title;
}
}
}

        包含在MenuCard中的类MenuItem(代码文件MenuCard/DataModel/MenuItem.cs)还定义了带有更改通知的简单属性:
using Wrox.Win8.Common;

namespace Wrox.Win8.DataModel
{
public class MenuItem : BindableBase
{
private string text;
public string Text
{
get { return text; }
set
{
SetProperty(ref text, value);
SetDirty();
}
}

private void SetDirty()
{
if (MenuCard != null)
{
MenuCard.SetDirty();
}
}

private double price;
public double Price
{
get { return price; }
set
{
SetProperty(ref price, value);
SetDirty();
}
}

public MenuCard MenuCard { get; set; }

}
}

类AddMenuCardInfo(代码文件MenuCard/DataModel/AddMenuCardInfo.cs)用于创建新菜单卡。这个类也是用于数据绑定的简单类型

using Windows.UI.Xaml.Media;
using Wrox.Win8.Common;

namespace Wrox.Win8.DataModel
{
public class AddMenuCardInfo : BindableBase
{
private string title;
public string Title
{
get { return title; }
set { SetProperty(ref title, value); }
}

private string description;
public string Description
{
get { return description; }
set { SetProperty(ref description, value); }
}

private ImageSource image;
public ImageSource Image
{
get { return image; }
set { SetProperty(ref image, value); }
}

private string imageFileName;
public string ImageFileName
{
get { return imageFileName; }
set { SetProperty(ref imageFileName, value); }
}
}
}

    类MenuCardFactory(代码文件MenuCard/DataModel/MenuCardFactory.cs)独立使用,可返回一个菜单卡列表。方法InitMenuCards用于初始化该集合,并把ObservableCollection赋予cards变量:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace Wrox.Win8.DataModel
{
public class MenuCardFactory
{
private ICollection cards;
public ICollection Cards
{
get
{
return cards;
}
}

public void InitMenuCards(IEnumerable menuCards)
{
cards = new ObservableCollection(menuCards);
}

private static MenuCardFactory instance = null;
public static MenuCardFactory Instance
{
get
{
return instance ?? (instance = new MenuCardFactory());
}
}
}
}

       这个应用程序用于创建菜单卡,但在第一次启动时,最好向用户显示一些初始的菜单卡。要创建示例数据,可使用MenuCardDataFactory类中的GetSampleMenuCards方法返回一组填充了一些菜单的菜单卡。示例菜单卡的图像存储在Assets文件夹中,从该文件夹中引用,例如Breakfast.jpg:
public static ObservableCollection GetSampleMenuCards()
{
Uri baseUri = new Uri("ms-appx:///");


var cards = new ObservableCollection();
MenuCard card1 = new MenuCard
{
Title = "Breakfast"
};
card1.MenuItems.Add(new MenuItem
{
Text = "Spezialfrühstück",
Price = 5.4,
MenuCard = card1
});
card1.MenuItems.Add(new MenuItem
{
Text = "Wiener Frühstück",
Price = 4.4,
MenuCard = card1
});
card1.MenuItems.Add(new MenuItem
{
Text = "Schinken mit 3 Eiern",
Price = 4.4,
MenuCard = card1
});
card1.ImagePath = string.Format("{0}{1}", baseUri, "Assets/Breakfast.jpg");
cards.Add(card1);


//... more menu cards in the code download


2.3  应用程序页面
现在向应用程序添加一些UI页面。从模板添加的第一个页面是MainPage.xaml。根据Blank App (XAML)模板,该页面没有提供任何结构,内容是完全可定制的。如果不创建Windows 8游戏或需要特殊布局的其他应用程序,最好使用标准的格式和样式,把应用程序名放在Windows 8样式规则准确定义的位置上。在开始运行不同的Windows 8应用程序时,会发现它们有一些相似之处。为了不重复工作,可以直接通过Visual Studio项模板,使用预定义的样式,如图5所示。
  《C#高级编程(第8版)》之用C# 2012和.NET 4.5编写Windows 8样式应用程序技巧_第6张图片
图5
    在示例应用程序中,前面创建的主页用Items Page模板替代。该应用程序创建的其他页面有基本页面(Basic Page)AddMenuCardPage和项页面(Items Page)MenuItemsPage。
    基本页面提供了一个布局,把应用程序名放在用户习惯查看的顶部位置。分割页面(Split Page)把页面分成两半,一半是列表,另一半是细节。
    项页面包含GridView控件,它在一个网格中显示项列表。要使用项组,可以使用模板Grouped Items Page、Group Detail Page和Item Detail Page。Grouped Items Page用于显示不同的项组,并使用带GroupStyle设置的ListView,以及带分组的CollectionViewSource。Group Detail Page显示一个组及其详细信息,于是为这个任务使用GridView。Item Detail Page使用RichTextBlock显示一项的细节,允许使用FlipView在项之间切换。


    使用这些模板在项目的Common目录中再添加更多的类:BindableBase可以用作一些数据类的基类,因为它实现了INotifyPropertyChanged接口;LayoutAwarePage是自定义页面的一个新基类,它可以通知旋转更改,提供旋转的可视化状态。BooleanNegationConverter和BooleanToVisibility- Converter是XAML实现IValueConverter的转换器,RichTextColumns类可以与RichTextBlock控件一起用于文本溢出。最后,SuspensionManager用于在应用程序挂起时,存储和加载应用程序的状态。

1. 主页
应用程序的主页如图6所示,它显示了每个菜单卡的标题和图像。
  《C#高级编程(第8版)》之用C# 2012和.NET 4.5编写Windows 8样式应用程序技巧_第7张图片
图6
    为此,只需要对XAML代码(代码文件MainPage.xaml)进行一些小的调整,如下代码所示。在Items Page模板中,XAML代码包含一个GridView作为子元素,有变化的是项模板从默认的Standard250×250ItemTemplate变成MenuCardItemTemplate,再添加一个ItemClick事件处理程序,在单击项时触发它:


    GridView的源代码用ItemsSource属性定义,它引用了静态资源itemsViewSource。itemsViewSource是在刚刚绑定到Items属性的页面资源中指定的一个简单CollectionViewSource:

    MenuCardItemTemplate在自定义样式文件Styles\MenuCardStyles.xaml中定义。默认模板中的项使用两列建立,而这里的项由两行组成。尺寸较大,且绑定到Image和Title属性上。记住,前面定义的MenuCard类实现了这些属性:















    前面定义的CollectionViewSource绑定到Items集合上。Items集合在MainPage类的方LoadState法中赋值(代码文件MenuCard/MainPage.xaml.cs)。LoadState方法的实现代码指定了LayoutAwarePage基类的DefaultViewModel属性。这个属性返回IObservableMap,其中任意数据对象都可以赋予一个键名。键名在XAML中用于引用数据。
protected override async void LoadState(Object navigationParameter,
Dictionary pageState)
{
var storage = new MenuCardStorage();
MenuCardFactory.Instance.InitMenuCards(new ObservableCollection(
await storage.ReadMenuCardsAsync()));
this.DefaultViewModel["Items"] = MenuCardFactory.Instance.Cards;
}


2. 添加菜单卡页面
    为了添加新的菜单卡,添加了AddMenuCardPage。这里使用的模板只是Basic Page模板。但是,其中没有太多的内容要定义。用户只需要给菜单卡指定标题、描述和图像。UI如图7所示,只需两个文本框、一个按钮和一个Image控件。
  《C#高级编程(第8版)》之用C# 2012和.NET 4.5编写Windows 8样式应用程序技巧_第8张图片
图7
    在AddMenuCard.xaml文件中定义主要控件的XAML代码如下所示。注意这里的两个要点:控件绑定到Image、Title和Description属性上,赋予父控件(Grid)的数据上下文被设置为Item属性:



















    在代码文件中,Item属性被赋予LoadState方法中AddMenuCardInfo类型的对象(它包含在XAML代码中绑定的属性) (代码文件AddMenuCardPage.xaml.cs):
private AddMenuCardInfo info = new AddMenuCardInfo();


protected override void LoadState(Object navigationParameter,
Dictionary pageState)
{
this.DefaultViewModel["Item"] = info;
}


3. 菜单项页面
    应用程序的第三个页面是MenuItemsPage,如图8所示。这个页面显示了一个菜单卡中的菜单项,并允许修改数据。
  《C#高级编程(第8版)》之用C# 2012和.NET 4.5编写Windows 8样式应用程序技巧_第9张图片
图8
    这个页面也基于Items Page模板,在LoadState方法中绑定到一组菜单项上(代码文件MenuItems- Page.xaml.cs):
protected override void LoadState(Object navigationParameter,
Dictionary pageState)
{
card = navigationParameter as MenuCard;
if (card != null)
{
this.DefaultViewModel["Items"] = card.MenuItems;
}
}


    有了3个页面后,就准备导航Windows 8应用程序。
三  应用程序工具栏
     尽管在chrome之前放置内容是Windows 8应用程序的一个重要设计方面,但显然用户需要一种方式与UI交互操作。现在这由新的应用程序工具栏(App Bar)提供。Windows以前的版本默认显示命令,而现在用户可以选择何时显示应用程序命令。
    通过触摸,轻击屏幕的底边界或顶边界时,应用程序工具栏就会显示出来。使用鼠标时,单击鼠标右键,会调用应用程序工具栏。使用键盘时,用户可以单击上下文菜单按钮。
    可以在页面的BottomAppBar和TopAppBar属性中定义应用程序工具栏。大多数应用程序都在底部显示应用程序工具栏。如果应用程序在顶部和底部都使用应用程序工具栏,它们就同时用相同的样式显示出来。
    下面的代码段(代码文件MainPage.xaml)在页面的BottomAppBar属性中定义了一个AppBar元素。在AppBar中,可以使用任何XAML元素定义应用程序工具栏的内容和布局。在这个示例中,添加了两个Button(按钮)控件,它们使用预定义的样式,并给Click事件添加了处理程序:










    在Visual Studio模板生成的样式文件中,已经有一些用于应用程序工具栏的预定义按钮。下面是示例代码使用的样式AddAppBarButtonStyle。这个样式仅使用Segoe UI Symbol字体系列定义了字符的值,以显示加号。除此之外,还用基本样式AppBarButtonStyle定义了轮廓线字形和TextBlock,来显示按钮的文本。


图9显示了带有应用程序工具栏的应用程序。
  《C#高级编程(第8版)》之用C# 2012和.NET 4.5编写Windows 8样式应用程序技巧_第10张图片
图9

小结:
    本文介绍了编写Windows 8应用程序的许多不同方面。XAML与编写WPF应用程序非常相似。数据绑定、内容控件和项控件一起使用。利用Visual State Manager处理不同的布局变化。Windows Runtime访问存储器,以读写数据和图像,使用移动存储器。使用FileOpenPicker,通过与用户交互来上传文件。本文还介绍了共享协定,它定义了提供数据的共享源和接收数据的共享目标。
    当然,设计Windows 8应用程序还有许多内容。还有更多的选择器(如联系人选择器),为应用程序提供文件打开选择器的协定;改进的搜索功能(允许应用程序使用toast给用户提供信息)等。



《C#高级编程(第8版)》试读电子书免费提供,有需要的留下邮箱,一有空即发送给大家。 别忘啦顶哦!

你可能感兴趣的:(开发技术,c#,解决方案,windows,8,编程,应用程序)