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

助手应用程序 – 搜索引擎、地理位置浏览器和语言翻译器集于一体

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.92/5 (9投票s)

2013年7月10日

CPOL

8分钟阅读

viewsIcon

49547

downloadIcon

345

助手应用程序:它本质上是一款为超极本设计的实用程序,集搜索工具、地理位置浏览工具和语言翻译工具于一体。

介绍 

关于该应用程序的总体介绍,它本质上是一款实用程序,集搜索工具、地理编码相关工具和翻译工具于一体。我选择展示这个应用程序作为“AppInnovation Contest”的参赛作品。   

用户将可以在一个应用程序中访问搜索、地理编码浏览和语言翻译。用户可以方便地搜索网络、查找当前位置并查询附近地点、以及互译不同语言。该应用程序将如同用户的助手,满足用户在搜索、地理编码浏览和翻译方面的基本和最基本的需求。 

背景 

该应用程序主要由微软技术和微软提供的 API 提供支持。此外,该应用程序需要用户拥有 Windows Live 账户密钥,作为访问搜索、地理编码和翻译的前提。用户首先需要从 Windows Azure 市场订阅(根据使用情况和需求,API 可能免费或收费),更多详情请访问:http://datamarket.azure.com/。 

最初,我构思了为 Windows Phone 7.1 开发此应用程序的想法,并且已接近完成,但随着超极本的出现,我也开始将其移植到 Windows 8 平台。 

演练 

下面解释的细节目前来自我的 Windows Phone 应用程序项目,在解释应用程序的过程中,我将列出目前要讨论的不同模块。您可以在网络上找到关于使用搜索、地理编码和翻译 API 的教程。我的项目使用了微软提供的 Bing API。模块如下:

1. 搜索模块 

2. 地理编码模块 

3. 翻译模块

一点点 GUI

在深入模块之前,我将简要讨论应用程序的 GUI 部分。随着 XAML 的出现,使用更少的精力设计 UI 变得更加容易和富有成效。XAML 教程链接:http://msdn.microsoft.com/en-us/library/ms752059.aspx 这是我一个页面的 GUI 代码。 

HomePage.xaml

<phone:PhoneApplicationPage 
    x:Class="MyPhoneApp.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="PortraitOrLandscape" Orientation="Portrait"
    shell:SystemTray.IsVisible="True" Loaded="PhoneApplicationPage_Loaded">
 
    <!--LayoutRoot is the root grid where all page content is placed-->
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="123"/>
            <RowDefinition Height="645"/>
        </Grid.RowDefinitions>
 
        <!--TitlePanel contains the name of the application and page title-->
        <StackPanel x:Name="TitlePanel" Margin="0,17,0,644" Grid.RowSpan="2">
            <TextBlock x:Name="ApplicationTitle" Text="Bing Factory!" 
               FontSize="30" Style="{StaticResource PhoneTextNormalStyle}" Width="467" />
            <TextBlock x:Name="PageTitle" Text="Login" Margin="9,-7,0,0" 
              FontSize="50"  Style="{StaticResource PhoneTextTitle1Style}" 
              Height="74" Width="469" />
        </StackPanel>
 
        <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Margin="0,0,0,34" Grid.Row="1">
        	<Grid RenderTransformOrigin="0.86,0.64" Margin="8">
        		<Grid.ColumnDefinitions>
        			<ColumnDefinition Width="154*"/>
        			<ColumnDefinition Width="154*"/>
        			<ColumnDefinition Width="154*"/>
        		</Grid.ColumnDefinitions>
        		<Grid.RowDefinitions>
        			<RowDefinition Height="198*"/>
        			<RowDefinition Height="198*"/>
        			<RowDefinition Height="198*"/>
        		</Grid.RowDefinitions>
        		<Image x:Name="img_Maps" Margin="8,29,8,30" 
        		    Source="Images/MapsLogo.png" Stretch="Fill" 
        		    Grid.Column="1" Tap="img_Maps_Tap" />
        		<Image x:Name="img_Search" Margin="8,29,8,30" 
        		  Source="Images/SearchLogo.png" Stretch="Fill" Tap="img_Search_Tap" />
        		<Image x:Name="img_Translator" Grid.Column="2" 
        		  Margin="8,29,8,30" Source="Images/TranslatorLogo.png" 
        		  Stretch="Fill" Tap="img_Translator_Tap" />
        	</Grid>
        </Grid>
    </Grid>
</phone:PhoneApplicationPage>

 Search.xaml

<phone:PhoneApplicationPage
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit" 
    x:Class="MyPhoneApp.WebSearch"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="PortraitOrLandscape"  Orientation="Portrait"
    mc:Ignorable="d" d:DesignHeight="800" d:DesignWidth="480">    
 
    <!--LayoutRoot is the root grid where all page content is placed-->
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
 
        <!--TitlePanel contains the name of the application and page title-->
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock x:Name="ApplicationTitle" Text="The Companion" 
              Style="{StaticResource PhoneTextNormalStyle}"/>
            <TextBlock x:Name="PageTitle" Text="Search" 
              Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
        </StackPanel>
 
        <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0" >
            <Grid.RowDefinitions>
                <RowDefinition Height="80"/>
                <RowDefinition Height="71" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
 
            <TextBox Height="72" HorizontalAlignment="Center"  Margin="1,8,0,0" 
               x:Name="txt_SearchText" VerticalAlignment="Top" Width="455" VerticalContentAlignment="Top" />
            <Button x:Name="btn_Search" Content="Search" Margin="171,79,159,0" 
              VerticalAlignment="Top" HorizontalAlignment="Center" Grid.RowSpan="2" Click="btn_Search_Click" />
            <ScrollViewer x:Name="ContentScroll" Grid.Row="2" 
                      HorizontalScrollBarVisibility="Auto" FontSize="18.667">
            <toolkit:WrapPanel x:Name="WrapPanel_Type" Height="72" Margin="1,14,0,0" 
                      Grid.Row="2" Width="364" VerticalAlignment="Top" HorizontalAlignment="Center" >
        		<CheckBox x:Name="chk_Web" Content="Web"  HorizontalAlignment="Center" 
        		  FontSize="18.667" Margin="0,0,0,-2" VerticalAlignment="Center" Checked="chk_Web_Checked" />
        		<CheckBox x:Name="chk_Images" Content="Images" Width="134" 
        		   HorizontalAlignment="Center" FontSize="18.667" Margin="4,0,0,-2" 
        		   VerticalAlignment="Center" Checked="chk_Images_Checked" />
        		<CheckBox x:Name="chk_Videos" Content="Video" Width="117" 
        		   HorizontalAlignment="Center" FontSize="18.667" Margin="250,-70,0,0" 
        		   Height="72" VerticalAlignment="Center" RenderTransformOrigin="0.752,0.486" 
        		   HorizontalContentAlignment="Center" Checked="chk_Videos_Checked" />
        	</toolkit:WrapPanel>
                </ScrollViewer>
            <ScrollViewer x:Name="ScrollViewerResult" Margin="11,16,5,0" Grid.Row="3">
 
                <ListBox x:Name="ListBox_Result" Height="382" HorizontalAlignment="Left" 
                     Margin="1,1,0,0"  VerticalAlignment="Top" Width="Auto" >
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Vertical" Width="Auto" Height="Auto" >
                                <TextBlock Style="{StaticResource PhoneTextNormalStyle}" 
                                  Text="{Binding Title}" TextWrapping="Wrap"/> 
                                <TextBlock Style="{StaticResource PhoneTextNormalStyle}" 
                                  Text="{Binding Description}" TextWrapping="Wrap" />
                                <TextBlock Style="{StaticResource PhoneTextNormalStyle}" 
                                  Text="{Binding DisplayUrl}" TextWrapping="Wrap" />
                                <TextBlock Style="{StaticResource PhoneTextNormalStyle}" 
                                  Text="{Binding Url}" TextWrapping="Wrap" Tap="Link_Tap" />
                                <Image Source="{Binding MediaUrl}" MaxHeight="40" MaxWidth="40"></Image>
                            </StackPanel>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>
 
            </ScrollViewer>
        </Grid>
    </Grid>
</phone:PhoneApplicationPage>

Search

关于 XAML 代码,我想补充一点,为了使 UI 更具交互性,XAML 提供了过渡效果,使应用程序在用户从一个页面导航到另一个页面时看起来更酷。要在 Silverlight 应用程序中生效过渡效果,需要在 app.xaml 文件的 InitializePhoneApplication 方法中从 TransitionFrame 而非 PhoneApplicationFrame 初始化 RootFrame。然后,可以在调用的页面的 OnNavigatedTo 和 OnNavigatedFrom 方法中重写以实现过渡。更多关于过渡效果的细节请参考教程:https://codeproject.org.cn/Articles/345129/Windows-Phone-7-Navigation-Transitions。使用 XAML 代码进行设计和效果方面还有很多可以探索的。我会说,探索越多,惊喜越多。

注册 API 

现在让我们来点编码内容。但在我们实际开始编码之前,我们需要确保我们能够访问将在应用程序中使用的 API。为了使用 Bing API 进行搜索、地图和翻译,需要拥有一个 Windows Live 账户。然后使用该 Live 账户在 Windows Azure Market Place 注册以订阅 Bing 搜索和 Microsoft Translator API。注册完成后,进入“我的账户”->“账户密钥”。在这里,您会找到最初提供的默认账户密钥。您也可以生成一个新的账户密钥,并使用它通过 API 进行身份验证,就像使用默认密钥一样。  

 Account Key 

要使用 Bing Maps API,请访问 https://www.bingmapsportal.com/ 并使用 Windows Live 账户在此注册。注册后,转到“创建或查看密钥”并为您的应用程序生成一个密钥。然后可以使用此密钥访问 Bing Maps API。 

Creating Map Key   
 

注意:我们已完成 API 注册。正如所注意到的,为了访问 API,我们需要账户密钥(用于搜索和翻译)和地图密钥(用于地图)。对于搜索和翻译 API,与 Bing Maps API 相比,它们是有限免费的。因此,我将让用户在应用程序中配置自己的账户密钥,以允许他们通过应用程序访问自己注册的 API(用于搜索和翻译),并使搜索和翻译能够正常工作。  

搜索 

由于 Bing 搜索访问注册已完成,我们可以从 Windows Azure Market Place 下载 .NET 类库 (BingSearchContainer.cs),方法是访问“我的账户”->“我的数据”->“Bing 搜索 API”页面,并将其包含在项目中。该类库内置了用于构建搜索查询(涉及网络、图像、视频等类别)的方法和设置变量。 

在同一位置“我的账户”->“我的数据”->“Bing 搜索 API”页面,导航到“探索此数据集”链接。在这里,您将找到搜索 API 的 URL,即“服务根 URL”。复制它并用于项目以执行搜索查询。下面列出了一些示例代码供参考。 

Private void btn_Search_Click(object sender, RoutedEventArgs e)
{
    try
    {
        var bingContainer = new BingSearchContainer(new Uri(
          "https://api.datamarket.azure.com/Data.ashx/Bing/Search/v1"));
        var accountKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
        
        bingContainer.Credentials = new NetworkCredential(accountKey, accountKey);
               
        if (chk_Web.IsChecked.Value)
        {
            var webQuery = bingContainer.Web(txt_SearchText.Text.Trim(), 
              "EnableHighlighting", "DisableQueryAlterations", 
              "en-IN", null, null, null, null);
            webQuery.BeginExecute(new AsyncCallback(this.WebResultLoadedCallback), webQuery); 
        }
        else if (chk_Images.IsChecked.Value)
        {
            var imageQuery = bingContainer.Image(txt_SearchText.Text.Trim(), 
              "EnableHighlighting","en-IN", null, null, null, string.Empty);
            imageQuery.BeginExecute(new AsyncCallback(this.ImageResultLoadedCallback), imageQuery); 
        }
        else if (chk_Videos.IsChecked.Value)
        {
            //Search the video results only
        }
        else
        {
            //Search All
        }
           
    }
    catch (Exception ex)
    { }

}

在 AsyncCallback 方法中使用从服务 API 获取的结果,将搜索结果绑定到任何数据容器,如网格、列表视图,以显示搜索结果。  

注意:要使用 BingSearchContainer.cs 类,需要在项目中添加对 System.Data.Services.Client dll 的引用。该 dll 用于请求 OData (Open Data Protocol) 服务(Bing API 服务)。有关 OData 协议的更多详细信息,请参阅:https://codeproject.org.cn/Articles/90365/An-overview-of-Open-Data-Protocol-OData

 

地理编码/地图 

Bing Maps 可用于开发,有两种方式。我们可以使用 Bing Map Task,也可以使用 Bing Maps API。在 Bing Map Task 的情况下,我们调用设备上安装的 Bing Maps;而对于 Map Control,我们将地图嵌入到我们的应用程序中(在应用程序中嵌入地图会消耗更多内存)。Bing Maps API 可用于需要根据我们的需求定制应用程序的场景。

Bing Maps Task 

使用地图任务启动地图提供了加载已安装的地图应用并设置默认中心位置或搜索词和缩放级别的选项。加载后,我们可以访问已安装的默认地图应用提供的各种功能,如当前位置、导航、搜索等。

bingMapsTask.Center = new GeoCoordinate(<Latitiude>, <Longitude>);
bingMapsTask.ZoomLevel = 2;
bingMapsTask.Show();
bingMapsTask.SearchTerm="search term" ;
bingMapsTask.ZoomLevel = 2;
bingMapsTask.Show();  

Bing Maps API

使用 Bing Maps API 需要将 Visual Studio 工具箱中提供的地图控件嵌入。将地图控件放在布局中,并在地图控件的 CredentialsProperty 中提供在 Bing Maps API 注册期间生成的密钥。 

<my:Map Height="309" HorizontalAlignment="Left" Margin="115,52,0,0" 
  Name="map1" CredentialsProvider="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" 
  VerticalAlignment="Top" Width="174" x:Name:Map/>

位置服务用于通过 GeoCoordinateWatcher 获取当前位置。GeoCoordinateWatcher 可用于在地理编码位置更改时更新用户的位置。下面提供了一个使用 GeoCoordinateWatcher 获取当前位置以及当前位置更改时的示例。

Private void GetCurrentPosition(object sender, RoutedEventArgs e) { if (watcher == null)
{
    watcher = new GeoCoordinateWatcher(GeoPositionAccuracy.High)
    {
        //---the minimum distance (in meters) to travel before the next
        MovementThreshold = 10
    };
                        
    //---event to fire when a new position is obtained---
    watcher.PositionChanged += new
    EventHandler<GeoPositionChangedEventArgs
    <GeoCoordinate>>(watcher_PositionChanged);

    //---event to fire when there is a status change in the location 
    
    watcher.StatusChanged += new
    EventHandler<GeoPositionStatusChangedEventArgs>
    (watcher_StatusChanged);
    watcher.Start();
}                    

protected void watcher_StatusChanged(object sender, GeoPositionStatusChangedEventArgs e)
{
    switch (e.Status)
    {
        case GeoPositionStatus.Disabled:
            //Custom message
            break;
        case GeoPositionStatus.Initializing:
            //Custom message
        case GeoPositionStatus.NoData:
            //Custom message
            break;
        case GeoPositionStatus.Ready:
            //Custom message
            break;
    }
}        
 
protected void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
{
    if(!e.Position.Location.IsUnknown)
    //Add pushpin to the location data recieved.
    {
        this.map.Center = new GeoCoordinate(e.Position.Location.Latitude, e.Position.Location.Longitude);
        //Removing previous location pushpin
        if (this.map.Children.Count != 0)
        {
            var pushpin = map.Children.FirstOrDefault(p => (p.GetType() == 
              typeof(Pushpin) && ((Pushpin)p).Tag == "locationPushpin"));
            if (pushpin != null)
            { this.map.Children.Remove(pushpin); }
        }
        //Adding current location pushpin
        Pushpin locationPushpin = new Pushpin();
        locationPushpin.Tag = "You are here";
        locationPushpin.Location = watcher.Position.Location;
        this.map.Children.Add(locationPushpin);
        this.map.SetView(watcher.Position.Location, 12.0);
    }
}

您还可以查询搜索位置。在这种情况下,需要将位置搜索查询构建为 REST 服务请求的形式,获取响应,最后处理响应。XML 或 JSON 都可用于此请求和响应与地图 API REST 服务会话。以下是一个创建位置查询和处理 XML 响应的非常好的示例:http://msdn.microsoft.com/en-us/library/hh534080.aspx.

//Example of a location query
string UrlRequest = "http://dev.virtualearth.net/REST/v1/Locations/" +
                                            queryString +
                                            "?output=xml" +
                                            " &key=" + BingMapsKey;      

反序列化响应后,获取当前的纬度和经度位置,并将其用于在地图上设置新位置并标记图钉。

注意:要使用地图控件,需要对 System.Devices.Location dll 添加引用;要使用图钉类,需要对 Microsoft.Phone.Controls.Maps DLL 添加引用。MSDN

翻译

要进行语言翻译,请从 Windows Azure Market Place 下载 .NET 类库(TranslatorContainer.cs),方法是访问“我的账户”->“我的数据”->“Microsoft Translator API”页面,并将其包含在项目中。该类库内置了用于构建翻译查询的方法和设置变量。

在同一位置“我的账户”->“我的数据”->“Microsoft Translator API”页面,导航到“探索此数据集”链接。在这里,您将找到翻译 API 的 URL,即“服务根 URL”。复制它并用于项目以执行翻译。Translator API 提供两种服务:一种是将输入文本翻译成特定语言,另一种是检测输入文本的语言。下面列出了一个翻译示例代码。

private void button1_Click(object sender, RoutedEventArgs e)
{
    TranslatorContainer translatorContainer = new TranslatorContainer(
      new Uri("https://api.datamarket.azure.com/Bing/MicrosoftTranslator/v1"));
    var accountKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";

    translatorContainer.Credentials = new NetworkCredential(accountKey, accountKey);

    var translationQuery = translatorContainer.Translate(
      "Translate this string", targetLanguage.Code, sourceLanguage.Code);

    var translationResults = translationQuery.BeginExecute(
      new AsyncCallback(this.TranslateResultLoadedCallback), translationQuery);
}

在 AsyncCallback 方法中,将获取的结果转换为 Translation 类型的列表,并仅收集列表的第一个成员作为最终翻译结果。请务必将结果转换为相应的语言文化,以便在 Windows Phone 上显示。有关 Windows Phone 支持的语言的详细信息,请参阅:http://msdn.microsoft.com/en-us/library/windowsphone/develop/hh202918(v=vs.92).aspx

var translationResults = new List<Translation>();
translationResults = result.ToList<Translation>();
// In case there were multiple results, pick the first one 
string translatedText = translationResults.First().ToString(new CultureInfo(translationCulture));

注意:要使用 TranslatorContainer.cs 类,需要在项目中添加对 System.Data.Services.Client.dll 的引用。

 

关注点

使用 API 似乎总是有趣的,并且随着新的操作系统平台的出现,为支持最新环境而开发新应用程序或转换旧应用程序变得势在必行。我曾计划在我的应用程序中包含语音识别功能以实现语音命令,但我被限制了,因为 Windows Phone 或 Metro 应用的开发环境没有 .NET (System.Speech.Recognition) 支持的语音识别引擎。但仍然有一种方法,我们可以使用 .NET 引用开发自己的服务,并将其本地托管在应用程序安装系统的 IIS 中。在这种情况下,语音识别甚至可以在 Metro 应用上轻松工作,因为我们只需要调用该服务就可以从音频输入中获取识别的文本。希望在我能在测试环境中实现这个想法后,尽快更新文章。

历史 

首次发布于 2012 年 10 月 14 日。助手应用程序。

© . All rights reserved.