• Windows Phone 8.1 开发实例 网络编程 天气预报


    首先感谢林政老师的博客,给了我很大的指导。

    准备工作

    我的开发环境:
    - Visual Studio 2013(With Update 4)
    - Windows Phone 8.1
    - Windows 8.1
    我使用的是百度天气的api,所以你需要一个百度天气的ak,戳这里申请。记住你ak的值,像这样拼接uri:
    http://api.map.baidu.com/telematics/v3/weather?location=城市&output=xml&ak=你的ak
    可以获取一个xml格式的返回数据:
    这里写图片描述

    具体思路

    Created with Raphaël 2.1.0异步获取数据解析xml绑定数据

    实现

    ForecastPeriod类,用来记录每天的天气和数据的绑定:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.ComponentModel;
    
    namespace WeatherForecastDIY
    {
        /// <summary>
        /// 天气预报数据类
        /// </summary>
        class ForecastPeriod:INotifyPropertyChanged
        {
            private string weather;//天气
            private string wind;//风力
            private string maxTemperature;//最高温
            private string minTemperature;//最低温
            private string date;//日期
            private string dayPictureUrl;//天气图片
            private string temperature;//温度
            public string Weather
            {
                set
                {
                    if (value != weather)
                    {
                        weather = value;
                        OnpropertyChanged("Weather");
                    }
                }
                get
                {
                    return weather;
                }
            }
            public string Wind
            {
                set
                {
                    if (value != wind)
                    {
                        wind = value;
                        OnpropertyChanged("Wind");
                    }
                }
                get
                {
                    return wind;
                }
            }
            public string MaxTemperature
            {
                set
                {
                    if (value != maxTemperature)
                    {
                        maxTemperature = value;
                        OnpropertyChanged("MaxTemperature");
                    }
                }
                get
                {
                    analysisTemperature();
                    return maxTemperature;
                }
            }
            public string MinTemperature
            {
                set
                {
                    if (value != minTemperature)
                    {
                        minTemperature = value;
                        OnpropertyChanged("MinTemperature");
                    }
                }
                get
                {
                    analysisTemperature();
                    return minTemperature;
                }
            }
            public string Date
            {
                set
                {
                    if (value != date)
                    {
                        date = value;
                        OnpropertyChanged("Date");
                    }
                }
                get
                {
                    return date;
                }
            }
            public string DayPictureUrl
            {
                set
                {
                    if (dayPictureUrl != value)
                    {
                        dayPictureUrl = value;
                        OnpropertyChanged("DayPictureUrl");
                    }
                }
                get
                {
                    return dayPictureUrl;
                }
            }
            public string Temperature
            {
                set
                {
                    if (value != temperature)
                    {
                        temperature = value;
                        OnpropertyChanged("Temperature");
                    }
                }
                get
                {
                    return temperature;
                }
            }
            /// <summary>
            /// 分析温度字符串,得到最高最低温
            /// </summary>
            private void analysisTemperature()
            {
                if (Temperature == null)
                    return;
                int p = -1;//波浪号的位置
                for (int i = 0; i < Temperature.Length; i++) 
                    if (Temperature[i] == '~') { p = i; break; }
                if(p==-1)//没有波浪号
                {
                    maxTemperature = Temperature;
                    minTemperature = Temperature;
                }
                else
                {
                    maxTemperature = Temperature.Substring(0, p) + "℃";
                    minTemperature = Temperature.Substring(p + 1, Temperature.Length - p - 1);
                }
            }
            public event PropertyChangedEventHandler PropertyChanged;
            protected void OnpropertyChanged(string name)
            {
                PropertyChangedEventHandler handler = PropertyChanged;
                if(handler!=null)
                {
                    handler(this, new PropertyChangedEventArgs(name));
                }
            }
        }
    }
    

    Forecast类,这个的主要功能是异步获取数据和解析Xml:

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Net;
    using System.Net.Http;
    using System.Xml;
    using System.Xml.Linq;
    using System.IO;
    using System.ComponentModel;
    using Windows.UI.Xaml;
    using Windows.Storage;
    
    namespace WeatherForecastDIY
    {
        /// <summary>
        /// 天气预报类
        /// </summary>
        class Forecast:INotifyPropertyChanged
        {
            private string city;//城市名
            private string currentTemperature;//实时的温度
            private Visibility vis;//控制进度条是否可见
            public string City
            {
                set
                {
                    if (city != value)
                    {
                        city = value;
                        OnpropertyChanged("City");
                    }
                }
                get
                {
                    return city;
                }
            }
            public string CurrentTemperature//实时气温
            {
                set
                {
                    if (currentTemperature != value)
                    {
                        currentTemperature = value;
                        OnpropertyChanged("CurrentTemperature");
                    }
                }
                get
                {
                    return currentTemperature;
                }
            }
            public ForecastPeriod TodayForecast//当天的天气
            {
                set;
                get;
            }
            public Visibility Vis
            {
                set
                {
                    if(value!=vis)
                    {
                        vis = value;
                        OnpropertyChanged("Vis");
                    }
                }
                get
                {
                    return vis;
                }
            }
            public ObservableCollection<ForecastPeriod> ForecastList { set; get; }//不知道多少天的天气集合
            /// <summary>
            /// 构造函数,初始化
            /// </summary>
            /// <param name="CityName"></param>
            public Forecast(string CityName)
            {
                City = CityName;
                ForecastList = new ObservableCollection<ForecastPeriod>();
                TodayForecast=new ForecastPeriod();
            }
            public Forecast()
            {
                City = "成都";//默认是成都萌萌哒
                ForecastList = new ObservableCollection<ForecastPeriod>();
                TodayForecast = new ForecastPeriod();
            }
            /// <summary>
            /// 异步获取天气预报
            /// </summary>
            /// <returns></returns>
            private async void getForecastAsync()
            {
                //异步一开始设置进度条可见
                Vis = Visibility.Visible;
                //局部变量
                ObservableCollection<ForecastPeriod> newForecastList = new ObservableCollection<ForecastPeriod>();
                //异步获取数据,很多童鞋问为啥uri要加DateTime,那是因为如果uri是一样的,不知道哪里的缓存就不让你更新数据
                Uri uri = new Uri("http://api.map.baidu.com/telematics/v3/weather?location=" + City + "&output=xml&ak=HyXsPscHkQOfR0nxyUmYrV8l&date=" + System.DateTime.Now.ToString());
                HttpClient httpClient = new HttpClient();
                HttpResponseMessage response = await httpClient.GetAsync(uri);
                response.EnsureSuccessStatusCode();
                Stream stream = await response.Content.ReadAsStreamAsync();
                //搞到Xlm
                XElement now = XElement.Load(stream);
                //用完释放好习惯
                httpClient.Dispose();
                //解析Xml,请对照着百度返回的Xml看
                //判断是否成功
                if(now.Element("status").Value.Equals("success"))
                {
                    //往下走啊往下走
                    now = now.Element("results").Element("weather_data").Element("date");
                    //这天的天气
                    ForecastPeriod newForecastPeriod = new ForecastPeriod();
                    //那一排Xml天气数据居然是并列的,解析解析
                    while (now != null) 
                    {
                        //获取当前节点的名字
                        string nowName=now.Name.LocalName;
                        if (nowName.Equals("date"))
                        {
                            string tmp = now.Value;
                            //当日期的长度大于2,就是当天的日期,那个有实时天气的(这个半夜会迷之失效,为啥问度娘)
                            if (tmp.Length > 2)
                            {
                                newForecastPeriod.Date = tmp.Substring(0, 2);
                                //简单的说就是在提取实时气温
                                int p = -1;
                                for (int i = 0; i < tmp.Length; i++) if (tmp[i] == ':') { p = i; break; }
                                CurrentTemperature = tmp.Substring(p + 1, tmp.Length - p - 3);
                            }
                            else
                                newForecastPeriod.Date = now.Value;
                        }
                        else if (nowName.Equals("dayPictureUrl"))
                            newForecastPeriod.DayPictureUrl = now.Value;
                        else if (nowName.Equals("weather"))
                            newForecastPeriod.Weather = now.Value;
                        else if (nowName.Equals("wind"))
                            newForecastPeriod.Wind = now.Value;
                        else if (nowName.Equals("temperature"))
                        {
                            //每次到气温的时候就结束了一天的预报,把这一天的情况加入集合
                            newForecastPeriod.Temperature = now.Value;
                            newForecastList.Add(newForecastPeriod);
                            newForecastPeriod = new ForecastPeriod();
                        }
                        now = (XElement)now.NextNode;
                    }
                    //终于解析完了(长吁一口气)
                    //接下来就是赋值了
                    TodayForecast.Weather = newForecastList[0].Weather;
                    TodayForecast.Wind = newForecastList[0].Wind;
                    TodayForecast.MaxTemperature = newForecastList[0].MaxTemperature;
                    TodayForecast.MinTemperature = newForecastList[0].MinTemperature;
    
                    foreach (ForecastPeriod forecastPeriod in newForecastList)
                        ForecastList.Add(forecastPeriod);
                }
                else
                {
                    //熊孩子一定乱输的城市,然后被度娘给了Error
                    //所以要纠正过来,还是默认成都萌萌哒
                    City = "成都";
                    //改应用数据
                    ApplicationDataContainer localsetting = Windows.Storage.ApplicationData.Current.LocalSettings;
                    localsetting.Values["City"] = City;
                    //这叫不叫递归调用呢?反正再来一次
                    getForecastAsync();
                }
                //终于异步完了,关掉进度条
                Vis = Visibility.Collapsed;
            }
            /// <summary>
            /// 没什么用的函数,懒得改了,大家明白那个意思就好
            /// </summary>
            public void getForecast()
            {
                getForecastAsync();
            }
    
            public event PropertyChangedEventHandler PropertyChanged;
            /// <summary>
            /// 绑定
            /// </summary>
            /// <param name="name"></param>
            protected void OnpropertyChanged(string name)
            {
                PropertyChangedEventHandler handler = PropertyChanged;
                if (handler != null)
                {
                    handler(this, new PropertyChangedEventArgs(name));
                }
            }
        }
    }

    主界面,设计得太丑,还望美工好的童鞋给予指导和建议:
    这里写图片描述这里写图片描述

    <Page
        x:Class="WeatherForecastDIY.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:WeatherForecastDIY"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Page.BottomAppBar>
            <CommandBar>
                <AppBarButton x:Name="Setting" Icon="Setting" Label="设置" Click="Setting_Click"/>
                <AppBarButton x:Name="Refresh" Icon="Refresh" Label="刷新" Click="Refresh_Click"/>
                <AppBarButton x:Name="SolidStar" Icon="SolidStar" Label="为我打分"/>
            </CommandBar>
        </Page.BottomAppBar>
    
        <Grid>
            <Pivot Title="{Binding City}">
                <PivotItem Header="今日">
                    <StackPanel x:Name="TodayStackPanel" Orientation="Horizontal">
                        <StackPanel x:Name="TodayWeatherStackPanel" Height="Auto" Width="15" Orientation="Vertical">
                            <TextBlock Text="天气  " TextWrapping="Wrap" Height="60" Width="Auto" FontSize="15"></TextBlock>
                            <TextBlock Text="{Binding Path=TodayForecast.Weather}" TextWrapping="Wrap" Height="Auto" Width="Auto" FontSize="15"></TextBlock> 
                        </StackPanel>
                        <StackPanel x:Name="TodayWindStackPanel" Height="Auto" Width="15" Orientation="Vertical">
                            <TextBlock Text="风力  " TextWrapping="Wrap" Height="60" Width="Auto" FontSize="15"></TextBlock>
                            <TextBlock Text="{Binding Path=TodayForecast.Wind}" TextWrapping="Wrap" Height="Auto" Width="Auto" FontSize="15"></TextBlock>
                        </StackPanel>
                        <StackPanel x:Name="TodayMaxTemStackPanel" Height="Auto" Width="15" Orientation="Vertical">
                            <TextBlock Text="最高温 " TextWrapping="Wrap" Height="60" Width="Auto" FontSize="15"></TextBlock>
                            <TextBlock Text="{Binding Path=TodayForecast.MaxTemperature}" TextWrapping="Wrap" Height="Auto" Width="Auto" FontSize="15"></TextBlock>
                        </StackPanel>
                        <StackPanel x:Name="TodayMinTemStackPanel" Height="Auto" Width="15" Orientation="Vertical">
                            <TextBlock Text="最低温 " TextWrapping="Wrap" Height="60" Width="Auto" FontSize="15"></TextBlock>
                            <TextBlock Text="{Binding Path=TodayForecast.MinTemperature}" TextWrapping="Wrap" Height="Auto" Width="Auto" FontSize="15"></TextBlock>
                        </StackPanel>
                        <TextBlock x:Name="CurrentTemperature" Height="240" Width="100" Text="{Binding CurrentTemperature}" VerticalAlignment="Top" FontSize="100" FontStyle="Normal"></TextBlock>
                        <TextBlock Text="℃" Height="90" Width="90" VerticalAlignment="Top" FontSize="50"></TextBlock>
                    </StackPanel>
                </PivotItem>
                <PivotItem Header="每天">
                    <Grid x:Name="EverydayWeatherGrid">
                        <ListBox x:Name="EverydayWeatherListBox" Background="White">
                            <ListBox.ItemTemplate>
                                <DataTemplate>
                                    <StackPanel Height="60" Width="Auto" Margin="0,0,0,15" Orientation="Horizontal">
                                        <TextBlock Text="{Binding Date}" Width="60" FontSize="30"></TextBlock>
                                        <Image Source="{Binding DayPictureUrl}" Width="60" Height="Auto"></Image>
                                        <TextBlock Text="{Binding Temperature}" Width="60" Height="Auto"></TextBlock>
                                    </StackPanel>
                                </DataTemplate>
                            </ListBox.ItemTemplate>
                        </ListBox>
                    </Grid>
                </PivotItem>
            </Pivot>
            <ProgressBar x:Name="ProgressBar" HorizontalAlignment="Left" Height="10" VerticalAlignment="Top" Visibility="{Binding Vis}" IsIndeterminate="True" Width="399.999969482422"/>
    
        </Grid>
    </Page>

    接下来是MainPage.xaml.cs,注释写得很详细:

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Runtime.InteropServices.WindowsRuntime;
    using Windows.Foundation;
    using Windows.Foundation.Collections;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Controls.Primitives;
    using Windows.UI.Xaml.Data;
    using Windows.UI.Xaml.Input;
    using Windows.UI.Xaml.Media;
    using Windows.UI.Xaml.Navigation;
    using Windows.Storage;
    
    // “空白页”项模板在 http://go.microsoft.com/fwlink/?LinkId=391641 上有介绍
    
    namespace WeatherForecastDIY
    {
        /// <summary>
        /// 可用于自身或导航至 Frame 内部的空白页。
        /// </summary>
        public sealed partial class MainPage : Page
        {
            private string city;//城市(我不是字幕君。。。)
            public string City
            {
                set
                {
                    if(value!=city)
                    {
                        city = value;
                    }
                }
                get
                {
                    return city;
                }
            }
            public MainPage()
            {
                this.InitializeComponent();
                this.NavigationCacheMode = NavigationCacheMode.Required;
                //第一次进来时就更新
                getCity();
                ReportForecast();
            }
            /// <summary>
            /// 报道天气
            /// </summary>
            private void ReportForecast()
            {
                Forecast forecast = new Forecast(City);
                forecast.getForecast();
                //数据绑定
                DataContext = forecast;
                EverydayWeatherListBox.ItemsSource = forecast.ForecastList;
            }
            /// <summary>
            /// 读应用数据的函数(突然意识到应该说方法,而不是函数)
            /// </summary>
            private void getCity()
            {
                ApplicationDataContainer localSettings = Windows.Storage.ApplicationData.Current.LocalSettings;
                if (!localSettings.Values.ContainsKey("City"))
                    localSettings.Values["City"] = "成都";//怎样都是成都萌萌哒
                City = localSettings.Values["City"].ToString();
            }
    
            /// <summary>
            /// 在此页将要在 Frame 中显示时进行调用。
            /// </summary>
            /// <param name="e">描述如何访问此页的事件数据。
            /// 此参数通常用于配置页。</param>
            protected override void OnNavigatedTo(NavigationEventArgs e)
            {
                // TODO: 准备此处显示的页面。
    
                // TODO: 如果您的应用程序包含多个页面,请确保
                // 通过注册以下事件来处理硬件“后退”按钮:
                // Windows.Phone.UI.Input.HardwareButtons.BackPressed 事件。
                // 如果使用由某些模板提供的 NavigationHelper,
                // 则系统会为您处理该事件。
                //上面一堆堆完全不知所以然,简单说就是这个界面从不见了到出现时调用这个方法
                getCity();
                ReportForecast();
            }
            /// <summary>
            /// 更新按钮
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void Refresh_Click(object sender, RoutedEventArgs e)
            {
                getCity();
                ReportForecast();
            }
            /// <summary>
            /// 设置按钮
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void Setting_Click(object sender, RoutedEventArgs e)
            {
                //调到SetCirt界面
                Frame.Navigate(typeof(SetCity), City);
            }
        }
    }
    

    接下来是SetCity的页面,也就是设置城市的页面,这个难点在于换页面。
    这里写图片描述
    设计:

    <Page
        x:Class="WeatherForecastDIY.SetCity"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:WeatherForecastDIY"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Page.BottomAppBar>
            <CommandBar>
                <AppBarButton x:Name="Accept" Icon="Accept" Label="确定" Click="Accept_Click"></AppBarButton>
                <AppBarButton x:Name="Cancel" Icon="Cancel" Label="取消" Click="Cancel_Click"></AppBarButton>
            </CommandBar>
        </Page.BottomAppBar>
        <Grid>
            <StackPanel x:Name="SetCityStackPanel">
                <TextBlock Margin="0,0,0,0" Height="15" FontSize="15" Text="输入城市"></TextBlock>
                <TextBox x:Name="TextBox" Height="15" Width="Auto" FontSize="15"></TextBox>
            </StackPanel>
        </Grid>
    </Page>
    

    SetCity.xaml.cs:

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Runtime.InteropServices.WindowsRuntime;
    using Windows.Foundation;
    using Windows.Foundation.Collections;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Controls.Primitives;
    using Windows.UI.Xaml.Data;
    using Windows.UI.Xaml.Input;
    using Windows.UI.Xaml.Media;
    using Windows.UI.Xaml.Navigation;
    using Windows.Storage;
    
    // “空白页”项模板在 http://go.microsoft.com/fwlink/?LinkID=390556 上有介绍
    
    namespace WeatherForecastDIY
    {
        /// <summary>
        /// 可用于自身或导航至 Frame 内部的空白页。
        /// </summary>
        public sealed partial class SetCity : Page
        {
            public SetCity()
            {
                this.InitializeComponent();
            }
    
            /// <summary>
            /// 在此页将要在 Frame 中显示时进行调用。
            /// </summary>
            /// <param name="e">描述如何访问此页的事件数据。
            /// 此参数通常用于配置页。</param>
            protected override void OnNavigatedTo(NavigationEventArgs e)
            {
                //想必大家都看见了上方微软君的迷之解释了吧。。。
                TextBox.Text = (string)e.Parameter;
            }
    
            private void Cancel_Click(object sender, RoutedEventArgs e)
            {
                TextBox.Text = "";
            }
            private void Accept_Click(object sender, RoutedEventArgs e)
            {
                //改改改,应用数据什么的
                ApplicationDataContainer localsetting = Windows.Storage.ApplicationData.Current.LocalSettings;
                localsetting.Values["City"] = TextBox.Text;
                //回到主界面
                Frame.GoBack();
            }
        }
    }
    
  • 相关阅读:
    MapReduce中压缩的使用体验
    weblogic 12安装及和Eclipse的整合
    常用正则表达式补充1
    C# 中利用 Conditional 定义条件方法
    金额文本框
    C#中的List<string>泛型类示例
    HTML ID和Name属性的区别
    CSS的position:fixed的使用
    C# 匿名方法和Lambda表达式
    C#设置开机启动程序
  • 原文地址:https://www.cnblogs.com/HarryGuo2012/p/4524039.html
Copyright © 2020-2023  润新知