到现在为止,我们只能显示一个城市的天气,可是如果想得到别的城市的天气呢,总不能去修改程序里的值啊.这样我们就需求添加一个选择城市的页面.
首先,我们要在MainPage.xaml页面中添加一个设置按钮,这个按钮呢,你自己做一个按钮也行,要是WM7为什么预留了一个ApplicationBar的功能,我们可以直接使用它就行,在每个xaml的页面中.这个功能的代码,已经为什么写好了,只是被注释掉了.它就在前台代码的最下面.
看到了,我们只要把它进行解开就行了.这里简单说一句<shell:ApplicationBarIconButton>就是
看到了吧,而且对于<shell:ApplicationBar.MenuItems>则是点击省略号后,显示的二级菜单位了,你可以自己去试一下.
一般来说我们刚解锁的这个applicationbar的图片全是X这个X表示的是没有图片.我们可以去SDK中去找我们自己需求的图片,地址是:
C;/programe file/Microsoft SDKs/window phone/v7.1/Icon/dark下面去选择你要的图片,然后将图片复制到你的项目中,然后修改图片的属性,Build Action:Content
Copy to Output: Copy if newer就可以了
/// <summary>
/// 设置按钮点击事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ApplicationBarIconButton_Click(object sender, EventArgs e)
{
NavigationService.Navigate(new Uri("/SetCity.xaml", UriKind.Relative));
}
SetCity.xaml页面就是我们的选择城市的页面,这里我们用到一个控制是LongListSelector控件,它需求你安装Silverlight for Windows Phone Toolkit才可以使用.http://silverlight.codeplex.com/releases/view/55034这个是它的下载地址.这个控件的好处是,可以让我们所选择的城市像电话号码薄一样显示出来,我们先看一下效果
看到了,是不是很好看,而且选择起来,也相当方便
我们看一下前台代码:
<phone:PhoneApplicationPage xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
x:Class="WeatherForecast.SetCity"
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"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True">
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="GroupHeader">
<Border Background="{StaticResource PhoneAccentBrush}" Margin="{StaticResource PhoneTouchTargetOverhang}" Padding="{StaticResource PhoneTouchTargetOverhang}">
<TextBlock Text="{Binding Key}"></TextBlock>
</Border>
</DataTemplate>
<DataTemplate x:Key="GroupItem">
<Border Background="{StaticResource PhoneAccentBrush}" Margin="{StaticResource PhoneTouchTargetOverhang}" Padding="{StaticResource PhoneTouchTargetOverhang}">
<TextBlock Text="{Binding Key}" Style="{StaticResource PhoneTextLargeStyle}"></TextBlock>
</Border>
</DataTemplate>
<DataTemplate x:Key="ListHeader">
<TextBlock Text="选择城市" Style="{StaticResource PhoneTextTitle1Style}"></TextBlock>
</DataTemplate>
<DataTemplate x:Key="Itemtmp">
<Grid>
<TextBlock Text="{Binding city}"></TextBlock>
</Grid>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
<!--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="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="page name" 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">
<toolkit:LongListSelector x:Name="llsCity" SelectionChanged="llsCity_SelectionChanged" Background="Transparent"
ItemTemplate="{StaticResource Itemtmp}"
ListHeaderTemplate="{StaticResource ListHeader}"
GroupHeaderTemplate="{StaticResource GroupHeader}"
GroupItemTemplate="{StaticResource GroupItem}">
</toolkit:LongListSelector>
</Grid>
</Grid>
<!--Sample code showing usage of ApplicationBar-->
<!--<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
<shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" Text="Button 1"/>
<shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" Text="Button 2"/>
<shell:ApplicationBar.MenuItems>
<shell:ApplicationBarMenuItem Text="MenuItem 1"/>
<shell:ApplicationBarMenuItem Text="MenuItem 2"/>
</shell:ApplicationBar.MenuItems>
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>-->
</phone:PhoneApplicationPage>
LongListSelector控件,可以让你自己设计它的样式模板,包括信息,头部等.这里我们就采用了默认情况.
我们来看后台代码,还记得在1中我给的哪个xml文件吗,里面的所有城市的信息.在这里我们要用它来做数据源.
第一步,我们先建立一个类,表示,省,市,以及市的ID
/// <summary>
/// 定义城市信息类
/// </summary>
public class CityInfo
{
public string city { get; set; }
public string province { get; set; }
public string cityid { get; set; }
}
第二步,我们要重载接口IGrouping主要是用来把得到的信息,拼接起来
/// <summary>
/// 定义城市信息类
/// </summary>
public class CityInfo
{
public string city { get; set; }
public string province { get; set; }
public string cityid { get; set; }
}
/// <summary>
/// 重载接口
/// </summary>
/// <typeparam name="TKey"><peparam>
/// <typeparam name="TElement"><peparam>
public class GroupingLayer<TKey, TElement> : IGrouping<TKey, TElement>
{
//分组数据
private readonly IGrouping<TKey, TElement> grouping;
//初始化
public GroupingLayer(IGrouping<TKey, TElement> unit)
{
grouping = unit;
}
//唯一的键值
public TKey Key
{
get { return grouping.Key; }
}
//重载判断相等方法
public override bool Equals(object obj)
{
GroupingLayer<TKey, TElement> that = obj as GroupingLayer<TKey, TElement>;
return (that != null) && (this.Key.Equals(that.Key));
}
public IEnumerator<TElement> GetEnumerator()
{
return grouping.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return grouping.GetEnumerator();
}
}
第三步,添加数据绑定代码
/// <summary>
/// 从XML数据中取出省份,市信息
/// </summary>
public void GetInfo()
{
var xDoc = XDocument.Load("data/city.xml");
List<CityInfo> listCity = new List<CityInfo>();
var info = from city in xDoc.Descendants("Citys")
select new
{
province = city.Element("province").Value,
cityc = city.Element("city").Value,
cityid = city.Element("cityid").Value
};
foreach (var c in info)
{
listCity.Add(new CityInfo() { province = c.province, city = c.cityc, cityid = c.cityid });
}
var selected = from c in listCity
group c by c.province into n
select new GroupingLayer<string, CityInfo>(n);
this.llsCity.ItemsSource = selected;
}
好,我们在构造函数中调用第三步的方法,来看一下效果,是不是显示出来,哪么显示之后,就是我们要点击城市之后,跳动回显示天气的页面,把选择的城市天气显示出来
这里的程序,就和(三)里的一样了,调用webclient写取得你要选择城市的天气.代码如下:
/// <summary>
/// 选择城市时对数据进行更新
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void llsCity_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
CityInfo c = this.llsCity.SelectedItem as CityInfo;
if (c!=null)
{
webclient(c.cityid);
}
}
/// <summary>
/// 加载远程中央气象局数据
/// </summary>
public void webclient(string cityid)
{
WebClient wc = new WebClient();
wc.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wc_DownloadStringCompleted);
wc.DownloadStringAsync(new Uri("http://m.weather.com.cn/data/" + cityid + ".html", UriKind.Absolute));
}
/// <summary>
/// 异步加载完成后,向气象类写数据
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
try
{
if (e.Result.Length < 1 || e.Error != null || e.Cancelled)
{
MessageBox.Show("天气预报数据加载失败!原因:" + e.Error.Message);
return;
}
JObject json = JObject.Parse(e.Result);
wi = new WeatherInfo
{
city = (string)json["weatherinfo"]["city"],
cityid = (string)json["weatherinfo"]["cityid"],
date_y = (string)json["weatherinfo"]["date_y"],
week = (string)json["weatherinfo"]["week"],
info = (string)json["weatherinfo"]["index48_d"],
wind1 = (string)json["weatherinfo"]["wind1"],
temp1 = (string)json["weatherinfo"]["temp1"],
temp2 = (string)json["weatherinfo"]["temp2"],
temp3 = (string)json["weatherinfo"]["temp3"],
temp4 = (string)json["weatherinfo"]["temp4"],
temp5 = (string)json["weatherinfo"]["temp5"],
weather1 = (string)json["weatherinfo"]["weather1"],
weather2 = (string)json["weatherinfo"]["weather2"],
weather3 = (string)json["weatherinfo"]["weather3"],
weather4 = (string)json["weatherinfo"]["weather4"],
weather5 = (string)json["weatherinfo"]["weather5"]
};
//Update();
UpdateXML(json);
}
catch (Exception ex)
{
MessageBox.Show("连接中央气象局出错!");
//ReadXml();
}
}
这里的UpdateXML方法,是用来更新我们的临时存储空间中的数据信息的,还记得上次我们说的吗.第一次加载的时候,会先加载的数据
/// <summary>
/// 更新XML文件,取得最新的数据
/// </summary>
/// <param name="json"></param>
public void UpdateXML(JObject json)
{
if (iso.FileExists("weatherData.xml"))
{
iso.DeleteFile("weatherData.xml");
IsolatedStorageFileStream isfs = new IsolatedStorageFileStream("weatherData.xml", FileMode.Create, iso);
XElement xe = new XElement("weatherInfo",
new XElement("city", (string)json["weatherinfo"]["city"]),
new XElement("cityid", (string)json["weatherinfo"]["cityid"]),
new XElement("date_y", (string)json["weatherinfo"]["date_y"]),
new XElement("week", (string)json["weatherinfo"]["week"]),
new XElement("temp1", (string)json["weatherinfo"]["temp1"]),
new XElement("temp2", (string)json["weatherinfo"]["temp2"]),
new XElement("temp3", (string)json["weatherinfo"]["temp3"]),
new XElement("temp4", (string)json["weatherinfo"]["temp4"]),
new XElement("temp5", (string)json["weatherinfo"]["temp5"]),
new XElement("temp6", (string)json["weatherinfo"]["temp6"]),
new XElement("weather1", (string)json["weatherinfo"]["weather1"]),
new XElement("weather2", (string)json["weatherinfo"]["weather2"]),
new XElement("weather3", (string)json["weatherinfo"]["weather3"]),
new XElement("weather4", (string)json["weatherinfo"]["weather4"]),
new XElement("weather5", (string)json["weatherinfo"]["weather5"]),
new XElement("weather6", (string)json["weatherinfo"]["weather6"]),
new XElement("wind1", (string)json["weatherinfo"]["wind1"]),
new XElement("wind2", (string)json["weatherinfo"]["wind2"]),
new XElement("wind3", (string)json["weatherinfo"]["wind3"]),
new XElement("wind4", (string)json["weatherinfo"]["wind4"]),
new XElement("wind5", (string)json["weatherinfo"]["wind5"]),
new XElement("wind6", (string)json["weatherinfo"]["wind6"]),
new XElement("info", (string)json["weatherinfo"]["index48_d"]));
XDocument xdoc = new XDocument(new XDeclaration("1.0", "utf-8", "yes"), new XComment("天气数据"), new XElement("root", xe));
StreamWriter sw = new StreamWriter(isfs);
xdoc.Save(sw);
sw.Close();
isfs.Close();
NavigationService.Navigate(new Uri("/MainPage.xaml?cityid=" + (string)json["weatherinfo"]["cityid"], UriKind.Relative));
}
}
运行一下看一下效果如何,呵呵.....是不是很有帅呢.这里其实还有几个问题,
第一,正常情况你,天气情况不应该是时时刷新的,应该设置一下,每隔几小时刷新一次,
第二,现在只是保留了一个城市的信息,你可以修改一下,做到保留几个城市的信息.