zoukankan      html  css  js  c++  java
  • C#版菜谱

    作者:马宁

    示例代码下载地址:https://files.cnblogs.com/aawolf/ContosoCookbook.zip

    Windows 8的Release Preview版已经在2012年的儿童节正式发布了。虽然不如外界期望的那么成熟,Windows 8开始慢慢的学步了。作为开发者,我们面临的挑战要大于之前Windows的每一次升级。Windows 8对于开发者的挑战,可能仅次于当年从DOS升到Windows,别忘了,无数在DOS下非常成功的软件因为无法支持Windows而在一夜间烟消云散。

    这次Windows 8的挑战主要来自于Metro UI,Metro UI是从Windows Phone衍生而来,适合移动设备多点触摸输入方式的UI Framework。而Metro UI的编程方式类似于Silverlight,结合了Windows Phone中的一些特点,但是Metro Style UI Framework却和两者都不相同。

    Metro UI支持三种编程语言:.NET(C#,VB.NET)、C++和JavaScript。在这些编程语言的下面,是统一的WinRT Framework。

    我们在这里就不多聊WinRT了,如果有兴趣的,可以去看微软的官方文档:

    http://msdn.microsoft.com/library/windows/apps/

    最近讨论C++和编程的比较多,反而是.NET编程有点冷清。所以,我在这里改写了一个例子,供大家参考。这个例子原本是JavaScript版的Contoso Cookbook,在Windows 8训练营时作为例子,应该很多人已JavaScript经拿到了。因为看不懂JavaScript,所以,我决定将其改写成C#版的。其中的图片的版权属于微软,如果有任何侵权问题,请通知我。我会进行更换。

    好了,接下来,言归正传。

    开发环境和创建工程

    我们的开发环境是Windows 8 Release Preview和Visual Studio Ultimate 2012 RC版。如果没有Visual Studio Ultimate 2012 RC版的朋友,也可以下载Visual Studio 2012 Express RC for Windows 8版,来开发Windows 8 Metro style应用。下载地址如下:

    http://msdn.microsoft.com/en-US/windows/apps/br229516.aspx

    3

    进入到Visual Studio 2012后,发现整个界面都很Metro,还能够切换黑背景和白背景,虽然图标变化较大,但是操作模式基本没有什么变化。所以,我们选择Visual C#下的Windows Metro style项目,其中包括了Grid App(XAML)选项,我们将工程名改为ContosoCookbook,点击OK。

    初次创建Windows 8的应用,需要申请开发者许可。目前是免费的,不知道将来是否要收费。点击“我同意”后,输入Live ID的用户名和密码即可。

    12

    然后,我们就进入到了Visual Studio 2012的主界面。主界面变化不大,我们选择直接运行应用程序,会进入到全屏的Metro UI界面,如下图所示:

    6

    这个形式也是Metro style里使用较多的一种展现形式。好坏就不评价了,大家慢慢适应吧。

    刚开始有一件郁闷的事情,不知道该怎么返回Visual Studio,在尝试了N多方法后,发现按Win键+D,可以直接返回Visual Studio。

    除了本机调试外,我们还能够使用模拟器来进行调试,想必这就是Windows 8平板以后的调试方式了。在工具栏的运行按钮后边有一个下拉菜单,选择“Simulator”,点击运行,会打开一个模拟器,如图:

    7

    这个模拟器中的状态和本机是一致的,包括安装的应用程序,但我们可以使用一些附加功能,来调试平板上特有的功能,比如:旋转、定位、摄像头等。最逗的是,这个模拟器没有关闭按钮,你唯一的办法就是,在模拟器中找到关机界面,然后将其关闭。

    修改应用名称和图标

    接下来,我们修改应用程序的启动界面和图标。在Solution Explorer中,找到Assets目录,其中需要修改的图标文件有:Logo.png(150x150), SmallLogo.png(30x30)和StoreLogo.png(50x50),启动界面是SplashScreen.png(620x300)。右键选中Assets,选择添加已有项目“Add - Existing Item”,将准备好的图片添加进来,覆盖掉默认的图标即可。

    8

    接下来,双击Package.appxmanifest文件,打开的是一个编辑器,可以设置与应用程序相关的属性。修改其中的Display name和Description属性,

    9

    除此之外,还有很多属性可以设置,在这里就不一一介绍了。Packaging属性页里,有一个Guid的属性,估计后边还可能出现Windows Phone上几个应用用一个Guid的情况了。

    修改完了Logo和显示名称之后,再次运行,可以看到新的界面。

    10

    加载数据和图片

    接下来就到了重头戏,要加载数据和图片了。首先在Solution Explorer中创建两个文件夹:data和images。data文件夹中添加Recipes.txt文件,其中包括了一组Json数据,包含了世界各地的美食介绍;images文件夹中,要包含所有的图片文件,直接将图片文件拖拽进去即可。

    然后,打开DataModel目录下的SampleDataSource.cs文件,在文件顶部添加引用:

    using Windows.Storage;
    
    using Windows.ApplicationModel;
    
    using Windows.Data.Json;

    然后在SampleDataSource类中增加一个新的方法来加载数据文件:

    public static async System.Threading.Tasks.Task LoadFile()
    
    {
    
    StorageFolder folder = await Package.Current.InstalledLocation.GetFolderAsync("data"); ;
    
    StorageFile file = await folder.GetFileAsync("Recipes.txt");
    
    string text = await FileIO.ReadTextAsync(file);
    
    }

    Windows 8文件访问方式发生了很大的变化,我花了一上午时间才搞定,最后的代码却很简单。调用Package.Current.InstalledLocation属性,就可以找到程序当前运行的路径,该属性返回一个StorageFolder对象。因为Recipes.txt文件放在data目录中,所以还要调用GetFolderAsync方法,来获取data子文件夹。GetFolderAsync方法是一个异步调用方法,所以我们需要使用一个新的关键字:await来等方法调用结束返回结果。await关键字只能在异步调用的方法中被调用,所以LoadFile方法声明时,增加了async关键字,表示该方法是一个异步调用方法。关于await和async关键字,我们以后有机会详细来说。

    获取了StorageFolder对象后,我们可以调用StorageFolder的GetFileAsync方法,来获取文件的StorageFile对象。然后再使用FileIO的ReadTextAsync方法,将文件读取到字符串中。

    好了,与文件相关的操作就介绍到这里。接下来,我们看一下,如何分析JSON数据。

    分析JSON数据

    随着JSON数据格式的流行,Metro style Framework也增加了对于JSON数据的支持。我们先来看看数据大概是什么样的:

    {"group":{"key":"Chinese","title":"Chinese","shortTitle":"Chinese","recipesCount":0,"description":"Lorem ipsum dolor sit amet","rank":"","backgroundImage":"images/Chinese/chinese_group_detail.png", "headerImage":"images/Chinese/chinese_group_header.png"},
    
    "key":1000,
    
    "title":"Chinese Salad",
    
    "shortTitle" : "Chinese Salad", 
    
    "preptime":30,
    
    "favorite":false,
    
    "rating": 3 , 
    
    "directions":"Preheat the broiler.",
    
    "backgroundImage":"images/Chinese/Chinese Salad.jpg",
    
    "ingredients":["1 head Napa or bok choy cabbage","1/4 cup sugar","1/4 teaspoon salt","3 tablespoons white vinegar","3 green onions","1 (3-ounce) package ramen noodles with seasoning pack","1 (6-ounce) package slivered almonds","1 tablespoon sesame seeds","1/2 cup vegetable oil"]},

    每项数据分属不同的Group,而我们需要的Group数据有:ID、标题、子标题、描述和标题图片;数据项的数据包括:Key、标题、子标题、背景图片和菜谱。

    所以,我们在LoadFile方法里增加下面的代码,代码略微有点长:

    JsonArray parsedResponse = JsonArray.Parse(text);
    
    if (parsedResponse.Count > 1)
    
    {
    
    string groupid = "";
    
    SampleDataGroup group1 = null;
    
    foreach (JsonValue value in parsedResponse)
    
    {
    
    var obj = value.GetObject();
    
    var group = obj["group"].GetObject();
    
    string id = group["key"].GetString();
    
    if (id != groupid)
    
    {
    
    groupid = id;
    
    group1 = new SampleDataGroup(
    
    group["key"].GetString(),
    
    group["title"].GetString(),
    
    group["shortTitle"].GetString(),
    
    group["headerImage"].GetString(),
    
    group["description"].GetString()
    
    );
    
    _sampleDataSource.AllGroups.Add(group1);
    
    }
    
    group1.Items.Add(new SampleDataItem(
    
    obj["key"].GetNumber().ToString(),
    
    obj["title"].GetString(),
    
    obj["shortTitle"].GetString(),
    
    obj["backgroundImage"].GetString(),
    
    obj["directions"].GetString(),
    
    ITEM_CONTENT, 
    
    group1)
    
    );
    
    }

    我们首先调用JsonArray.Parse方法来解析刚刚获取到的Json数据,返回一个JsonArray的数组对象。接下来,通过foreach来遍历JsonArray中的数据项,获取到的对象是JsonValue对象。因为获取到的数据是对象,所以,我们使用JsonValue的GetObject方法来获取一个对象,虽然代码里用的是var,实际的数据类型是JsonObject。然后用obj["group"].GetObject()方法来获取到Group信息的JsonObject,中括号中必须填写Key的名称。然后取出Group的Id值,该值是一个字符串,所以调用GetString方法来获取Id值。如果读取出的Id值与之前不同,则创建新的SampleDataGroup对象,对象中所需的数据则通过Group对象的GetString方法来获取;然后,将其添加到SampleDataSource 的AllGroups属性中。

    接下来,就是创建SampleDataItem对象,这次要从obj对象里取到所需信息,如果JSON数据中是数字,则调用GetNumber方法。最后将创建好的SampleDataItem对象添加到SampleDataGroup的Items列表中。

    到这里,我们关于JSON的代码就写完了。接下来,摆在我们面前的还有一个问题。

    解决异步调用的问题

    接下来的代码似乎顺理成章了。我们在SampleDataSource的构造函数中,将里边的示例代码全部删除,然后添加LoadFile方法,如下图:

    public SampleDataSource()
    
    {
    
    LoadFile();
    
    }

    运行之后的效果却是如下:

    clip_image016

    Group的数据被加载了,但是其中的数据项未被加载。而我们点击Chinese项目时,则能够看到中国美食的情况,再退回主界面,所有的数据就能够显示出来了。这是典型的异步调用错误。原因也很简单,是因为SampleDataSource的构造函数是同步调用,不会等LoadFile结束后再返回,所以,当界面上显示数据时,显示的只是未加载完成的数据列表。

    头疼的问题啊,我试了几种方案,最后采取的这种方案未必是最好的,但确实能够解决这个问题。也许大家有更好的解决方法,留一个悬疑吧。接下来,我说我的办法。

    由于构造函数无法变成async调用方法,所以只能用另外的一个显式初始化函数来替代构造函数的作用,在数据显示之前,显式地调用该初始化函数。所以,我就直接将LoadFile作为这个初始化函数,为LoadFile增加public,static和async关键字。

    然后,我们打开GroupItemsPage.xaml.cs文件,找到LoadState方法。该方法用来设置当前视图的数据源,所以,我们在LoadState方法的顶部显式调用SampleDataSource.LoadFile方法。当然,我们会得到一个编译错误,因为LoadState方法也是一个同步调用函数,简单地为LoadState方法增加一个async的关键字就可以解决这个问题。代码如下:

    protected async override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
    
    {
    
    await SampleDataSource.LoadFile();
    
    var sampleDataGroups = SampleDataSource.GetGroups((String)navigationParameter);
    
    this.DefaultViewModel["Groups"] = sampleDataGroups;
    
    }

    好了,当我们终于做完这一切之后,我们就可以看到完整的用户界面了:

    clip_image018

    clip_image020

    clip_image022

    写在最后

    看起来很简单的代码,却整整写了一天,期间试过的方法也很多,一言难尽。目前Windows 8的开发资料也比较少,我在开发过程中,找到了下面的例子“Windows 8 Release Preview Metro style app samples - C#, VB.NET, C++, JavaScript”,在其中找到很多有用的代码:

    http://code.msdn.microsoft.com/windowsapps/Windows-8-Modern-Style-App-Samples

    好了,这次的例子包括了数据绑定、JSON数据分析和文件读取,希望后边还有时间能够写更多的例子出来。

  • 相关阅读:
    LeetCode 227. Basic Calculator II
    LeetCode 224. Basic Calculator
    LeetCode 103. Binary Tree Zigzag Level Order Traversal
    LeetCode 102. Binary Tree Level Order Traversal
    LeetCode 106. Construct Binary Tree from Inorder and Postorder Traversal
    LeetCode 105. Construct Binary Tree from Preorder and Inorder Traversal
    LeetCode 169. Majority Element
    LeetCode 145. Binary Tree Postorder Traversal
    LeetCode 94. Binary Tree Inorder Traversal
    LeetCode 144. Binary Tree Preorder Traversal
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2532330.html
Copyright © 2011-2022 走看看