65.9K
CodeProject 正在变化。 阅读更多。
Home

Windows Phone 7 Silverlight 开发入门:制作离线 RSS 阅读器

2010 年 7 月 3 日

CPOL

7分钟阅读

viewsIcon

79724

downloadIcon

2056

Windows Phone 7 Silverlight 开发入门:制作离线 RSS 阅读器

引言

几个月后,微软将推出其移动操作系统 Windows Phone 7 的新版本,带来许多新的、有争议的、支持者和反对者……

但今天,让我们从程序员的角度来看。微软为使用 WPF/Silverlight 的人提供了巨大的优势。目前,我们也是 Windows Phone 7 的开发者,因为这个操作系统上的所有应用程序都是用 XNA 或 Silverlight 开发的。

与 Windows Mobile 6.X 或其他竞争对手的移动平台相比,这是一场革命,因为它将允许我们以快速简单的方式移植已经在 Silverlight 上运行的应用程序,几乎不需要重写代码。

为了让大家了解一些 Silverlight for Windows Phone 7 应用程序的开发示例,我为大家带来了一个 RSS 阅读器(非常基础,没有商业抱负或其他任何东西),我们将在其中使用 Silverlight 和 Windows Phone 7 的几个有趣之处

  • 应用程序栏
  • 访问我们终端的本地存储
  • 对象序列化和反序列化
  • 使用 WebClient
  • 使用 webBrowser 控件加载动态生成的内容

我们应用程序的最终结果

Captura_2.PNG

开始

为了开发 Windows 7 Phone 应用程序,您需要在此处下载开发工具的 CTP。

此包包含 Visual Studio 2010 Express for Windows Phone,因此如果您没有 Visual Studio 2010,您在开发 Windows Phone 7 时不会遇到问题。

安装开发工具后,只需打开 Visual Studio 2010 并选择一个新的 Silverlight for Windows Phone 项目,如图所示

Captura3.PNG

该项目是 Visual C#,不要寻找 Visual Basic,它还没有找到。目前,只支持 C#,但 Windows Phone 承诺 SDK 的最终版本将支持 Visual Basic。但最终,所有这些都是 .NET,这两种语言并没有太大变化。

应用程序栏

ApplicationBar 是 Windows Phone 7 团队的一个绝妙设计理念,旨在帮助我们创建应用程序界面,您可以在此捕获中详细查看

Captura4.PNG

底部紫色的带有 3 个点的条是应用程序栏,点击 3 个点会显示所有可用选项

Captura5.PNG

它非常有用,因为它允许我们创建一个菜单,只需添加一个引用即可包含在应用程序的每个页面上,因为菜单的定义在 App.xaml 文件中,每个选项关联的代码在 app.xaml.cs 文件中。考虑定义应用程序 XAML 栏所需的代码。

首先,我们的项目应该包含对 Microsoft.Phone.Shell 程序集的引用。

然后,我们的 App.xaml 应该包含对 Microsoft.Phone.Shell 的引用

xmlns:shell="clr-namespace:Microsoft.Phone.Shell;
             assembly=Microsoft.Phone.Shell"

最后在 <Application.Resources> 标签中,创建我们的应用程序栏

<shell:ApplicationBar x:Name="MenuAppBar" Opacity="0.7"
                       IsVisible="True" IsMenuEnabled="True"
                       BackgroundColor="Purple" >
    <shell:ApplicationBar.MenuItems>
        <shell:ApplicationBarMenuItem Text="Edit Rss Sources"
                                       x:Name="EditRss"
                                       Click="EditRss_Click"/>
        <shell:ApplicationBarMenuItem Text="Update Local Rss"
                                       x:Name="UpdateRss"
                                       Click="UpdateRss_Click"/>
        <shell:ApplicationBarMenuItem Text="View Local Rss"
                                       x:Name="ViewRss"
                                       Click="ViewRss_Click"/>
    </shell:ApplicationBar.MenuItems>
</shell:ApplicationBar>

现在,在您想要显示 ApplicationBar 的每个页面上,您必须指示对象 <navigation:PhoneApplicationPage>ApplicationBar 属性

<navigation:PhoneApplicationPage
     ...
     ...
    ApplicationBar="{StaticResource MenuAppBar}">

这样,如果我们运行我们的应用程序,我们将看到我们的应用程序栏出现并显示所有选项。

要为每个选项添加代码,我们使用前面在 XAML 中定义的 Click 事件,例如,“编辑 RSS 源”选项调用事件 EditRss_Click,它位于 app.xaml.cs 文件中并具有此签名

private void EditRss_Click(object sender, EventArgs e)
{
    //Do something awesome here!
} 

如您所见,方法 EditRss_Click 的签名与任何按钮的 Click 事件的签名相同。

访问本地存储、序列化和反序列化对象

Windows Mobile 6.X 和 Windows Phone 7 之间开发的一个主要变化是,我们的应用程序没有权限访问存储在终端上的通用存储,也无法使用终端中的数据库。

微软对这一指导方针很明确:将您的数据移动到云端,您的应用程序可以通过您的互联网连接访问它们。虽然这完全正确,但我们有时会希望在终端上存储一些信息,例如数据缓存或存储应用程序上的用户偏好及其状态。我们通过访问分配给我们的应用程序的 IsolatedStorage 来实现此目的。此存储空间与系统和应用程序的其余部分隔离,并且专属于我们的应用程序。

假设我们希望在此隔离存储中保存一个文件,其中包含我们在应用程序中配置的所有 RSS 源。这使用 XML 序列化和反序列化以及用必要的 XML 属性装饰我们的类非常简单。

为此,我们首先需要将对 System.Xml.Serialization 程序集的引用添加到我们的项目中。

首先,让我们创建一个类,该类可以存储我们想要为每个 RSS 保留的信息

/* A simple class to store rss information. */
public class RssSource
{
    //Public Properties:
    [System.Xml.Serialization.XmlElement]
    public String Description { get; set; }
    [System.Xml.Serialization.XmlElement]
    public String Url { get; set; }
    //Constructors:
    public RssSource()
    {
    }
    public RssSource(String SourceDesc, String SourceUrl)
    {
        Description = SourceDesc;
        Url = SourceUrl;
    }
}

如您所见,它是一个非常简单的类,具有两个 public 属性用于存储 RSS URL 和描述以及两个构造函数。

如果您查看此类的属性,您会发现它们都用属性 System.Xml.Serialization.XmlElement 装饰,这用于让 XML 序列化器知道每个属性代表一个 XML 元素节点。

现在,由于我们将在文件中存储多个 RSS 源,因此我们创建另一个类,该类将被序列化,并且它还将具有添加、删除、保存和加载我们的源列表的功能

/* A simple class to manage rss sources */
public class RssSources
{
    //Public List with all rss sources.
    [System.Xml.Serialization.XmlArray]
    public List<RssSource> Sources = new List<RssSource>();
    //Constructor.
    public RssSources()
    {
     
    }
    //Load rss sources saved to Isolated Storage.
    public bool LoadFromIso()
    {
        XmlSerializer Serializator = new XmlSerializer(typeof(RssSources));
        IsolatedStorageFile IsoFile = IsolatedStorageFile.GetUserStoreForApplication();
        IsolatedStorageFileStream Stream = IsoFile.OpenFile("Sources.rss", 
           FileMode.OpenOrCreate);
        try
        {
            RssSources DiskSources = (RssSources)Serializator.Deserialize(Stream);
            this.Sources = DiskSources.Sources;
            return true;
        }
        catch (Exception)
        {
            return false;
        }
        finally
        {
            Stream.Close();
            IsoFile.Dispose();
        }
    }
    //Add new rss source to the list.
    public bool AddSource(String Description, String Url)
    {
        try
        {
            Sources.Add(new RssSource(Description, Url));
            SaveToIso();
            return true;
        }
        catch (Exception)
        {
            return false;
        }
    }
    //Delete rss source from the list.
    public bool DeleteSource(RssSource Item)
    {
        try
        {
            Sources.Remove(Item);
            return true;
        }
        catch (Exception)
        {
            return false;
        }
    }
    //Save current List of rss sources to Isolated Storage
    private bool SaveToIso()
    {
        XmlSerializer Serializator = new XmlSerializer(typeof(RssSources));
        IsolatedStorageFile IsoFile = IsolatedStorageFile.GetUserStoreForApplication();
        if (IsoFile.FileExists("Sources.rss"))
             {
                 IsoFile.DeleteFile("Sources.rss");
             }
        IsolatedStorageFileStream Stream = IsoFile.CreateFile("Sources.rss");
        try
        {
            Serializator.Serialize(Stream, this);
            return true;
        }
        catch (Exception)
        {
            return false;
        }
        finally
        {
            Stream.Close();
            IsoFile.Dispose();
        }
    }
}

好的,此类公开了一个 RssSource 类型的列表(您之前创建的基类)、一个无参数构造函数和四个方法

  • AddSource:只需向 Sources 列表添加一个新的 RssSource
  • DeleteSource:从源列表中删除一个现有项目。
  • SaveToIso:使用 XmlSerializer 类,创建与我们的类相同类型的序列化器,我们获取我们应用程序的 IsolatedStore 并创建一个 IsolatedSorageFileStream,最后将我们类的内容序列化到此文件。
  • LoadFromIsoSaveToIso 方法的反向操作,我们打开一个包含我们类序列化和反序列化后的文件,以获取其中包含的 RssSource 列表。

如果您检查代码,您会发现它非常简单,并允许我们以非常简单和快速的方式存储信息,当然不能替代数据库,但对于小块数据或物理持久化我们应用程序对象的壮态非常有用。

使用 WebClient 类

好的,我们已经存储了我们的 RSS 源,但是如何从中获取内容呢?很简单,使用 Silverlight 中的 WebClient

这个类允许您异步地从 URI 下载文本格式的内容,所以首先要做的是声明一个响应 WebClient 类事件 DownloadStringCompleted 的方法

 private void DownloadComplete(object sender, DownloadStringCompletedEventArgs e)
{
    var client = sender as WebClient;
    if (client != null)
    {
        client.DownloadStringCompleted -= DownloadComplete;
    }
    if (e.Error != null)
    {
        throw e.Error;
    }
    if (e.Result != null)
    {
        //e.Result contains a String with the downloaded data.
    }
}

e.Result 包含下载的文本,在我们的例子中包含我们下载的不同 XML RSS 新闻。在示例项目中,我使用 LINQ to XML 来获取所有新闻并将它们保存到一个泛型列表中。

一旦我们定义了 DownloadStringCompleted 事件处理程序,我们只需创建对象并告诉 WebClient 下载 RSS

WebClient client = new WebClient();
client.DownloadStringCompleted += DownloadComplete;
client.DownloadStringAsync(new Uri(RssUrl));

使用 webBrowser 控件加载动态生成的内容

最后一步是显示新闻内容,通常内容是带有图像和其他标签的 HTML 格式,因此更适合使用 WebBrowser 控件在网页中显示内容,为此只需将头部和主体添加到我们的新闻中,并使用 WebBrowser 控件的 NavigateToString 方法来显示我们的 HTML

webBrowser1.NavigateToString(
        "<html><head><meta name='viewport' " + 
 "content='width=480, user-scalable=yes'/>" + 
 "</head><body>" +
        (lstDetails.SelectedItem as RssFeed).Description +
        "</body></html>");

使用这段简单的代码,任何文本字符串都可以在 webbrowser 控件中显示,就像它是一个网页一样。

就是这样。您可以下载附加的项目以查看所有实际操作。

希望您喜欢。快乐编码!欢迎大家阅读,谢谢!

历史

  • 2010 年 7 月 2 日 - 第一个版本
  • 2010 年 7 月 15 日 - 更新到微软几天前发布的新的开发者工具 Beta 版
    • 现在使用 Microsoft.Phone 程序集替换 Microsoft.Phone.ControlsMicrosoft.Phone.NavigationMicrosoft.Phone.Shell 等...
    • PhoneApplicationPage 对象现在位于 Microsoft.Phone.Controls 命名空间中,而不是像 CTP 版本那样位于 Microsoft.Phone.Navigation
    • 删除了所有 UIElement.Effect 引用,Beta 版本不允许
    • 我们应用程序的主页现在定义在 Properties 下的 WMAppManifest.xml 文件中,在 <Tasks><DefaultTask></DefaultTask></Tasks> 部分
    • 发布了更新到 Beta 版本的新示例代码,其中包含所有更改。
© . All rights reserved.