使用自定义控件预测天气

分享于 

17分钟阅读

Web开发

  繁體

介绍

本文描述了一个自定义控件的构造,该控件用于根据指定的邮政编码显示三天天气预报。 控件由 public,免费web服务驱动,该服务返回美国的任何区域的邮政编码或者位置的七天预测。 这个演示仅使用七天预测的前三天,并且仅实现基于基于邮件的预测数据的请求。

除了返回天气预报外,web服务还返回 NAME ( 比如,城市)。状态和纬度/经度对。 它还返回了一些其他可能引起兴趣的东西,比如位置的FIPS代码。

web服务的另一个有趣特性是,它还返回一个反映预测( 比如,外面下雨的照片,或者是晴天的照片)的图像的路径。 利用含降水的预报图像,降水百分比也显示为预测图像的附加值。 这里路径用于在激活服务方法"getweatherbyzipcode"的web站点时动态加载图像。

在使用该控件时,如果要保留用户代码或者将它的保持在用户的机器上,用户将看到它的特定地理位置。 在演示项目中,示例提供了使用预设的zip编码初始化的控件,并且可以动态地更改zip代码。

相关下载包括控件本身和演示网站的源代码。 public 美国预测网络服务可以在以下地址找到: http://www.webservicex.net/WS/WSDetails.aspx?CATID=12&WSID=68

图 1: 使用中的天气预报自定义控件

入门

包含的文件包括一个网页控制库项目和一个示范网站。 要开始,打开包含的压缩文件并将两个项目安装到你的文件系统中。 打开IIS并为web应用程序创建一个虚拟目录。 将解决方案打开到可视化 2005并进行任何必要的更改以使两个项目都进入解决方案。 配置好后,解决方案资源管理器应该显示这些项目,引用和文件:

图 2: 带有网络应用程序和控制库的解决方案资源管理器

在检查解决方案时,注意"WeatherReport"控件库只包含一个控件,该控件称为"预测"。 这里项目还包括指向 http://www.webservicex.net 站点的web引用;这里 public 站点提供用于捕获控件显示的美国气象预报信息。

web应用程序只包含一个网页( Default.aspx ),并包含对"WeatherReport"dll的引用。

web应用程序用作测试自定义控件的容器;Default.aspx 页包含一个预测控件以及用于更改应用的邮件。 网页上显示的日历仅供eyewash使用,超链接将打开一个新窗口,显示服务代码查找页面。

代码:预测

在初始化过程中构造" Forecast"自定义控件来检索来自web服务的信息,并使用该信息显示天气预报的前七天。 在这个演示中,我维护了视图状态的zip代码,但是每次控件初始化时都会提供预测数据。 更好地维护视图状态中的所有预测值,并只更新邮件后更新邮件后的回复事件。 为了保持代码简短,我选择在这个演示中不这么做。

web服务作为名为 WeatherForecasts的类返回请求的数据,每个日的天气细节都包含为一组名为 WeatherDetails的附属类。 WeatherForecasts 对象包含有关位置( 城市,州,纬度,经度,等等 )的信息,WeatherDetails 包含日期。最小和最大温度( 度F 和度C ) 和适当的天气预报图像。

在检查代码时,请注意,项目中只包含默认导入。 类本身从 WebControl 类继承。

Imports SystemImports System.Collections.GenericImports System.ComponentModelImports System.TextImports System.WebImports System.Web.UIImports System.Web.UI.WebControlsImports System.Xml
<ToolboxData("<{0}:Forecast runat="server"></{0}:Forecast>")> _PublicClass Forecast
 Inherits WebControl

在类声明之后,创建一个名为"声明"的区域,在该区域中,该区域是在该控件中使用的private 成员变量的声明。

#Region"Declarations" 
 Private mForecast As net.webservicex.www.WeatherForecast
 Private WxDetails() As net.webservicex.www.WeatherData
 Private Wx As net.webservicex.www.WeatherForecasts#End Region

声明变量之后,定义了另一个区域,在该区域中,用于捕获来自web服务的数据并填充成员变量的代码是。 初始化处理程序每次初始化控件时调用名为"getweather"的子例程。 GetWeather 以字符串的形式接受单个参数,该字符串包含五个数字邮政编码。

GetWeather 中,mForecast 对象被定义为 Web服务 天气预报类的新实例。 从这个类别中,天气报告和天气细节被捕获并分配给适当的变量。 在呈现过程中直接使用这些变量来定义控件的内容。

方法区域中包含的代码如下所示:

#Region"Methods" 
 PrivateSub Forecast_Init(ByVal sender AsObject, _
 ByVal e As System.EventArgs) _
 HandlesMe.Init
 IfNotString.IsNullOrEmpty(ZipCode) Then GetWeather(ZipCode)
 Else GetWeather("36201")
 EndIfEndSubPublicSub GetWeather(ByVal zip AsString)
 Try mForecast = New net.webservicex.www.WeatherForecast
 Wx = mForecast.GetWeatherByZipCode(zip)
 WxDetails = Wx.Details
 CatchExitSubEndTryEndSub#End Region

代码中定义的下一个区域称为"属性";这个部分包含控件使用的属性。 在这种情况下,除了通过 WebControl 类传递之外,定义的唯一属性是用于包含zip代码的字符串值。

为了使这一点更有效率,最好将天气预报和气象细节储存到视图状态或者控制状态。

属性区域及其单个属性的定义如下:

#Region"Properties" 
 <Category("Weather"), _
 Description("Set Forecast Zip Code"), Browsable(True)> _
 Property ZipCode() AsStringGetDim s AsString = CStr(ViewState("ZipCode"))
 If s IsNothingThenReturnString.Empty
 ElseReturn s
 EndIfEndGetSet(ByVal Value AsString)
 ViewState("ZipCode") = Value
 EndSetEndProperty#End Region

类别。可以浏览和描述的属性用于为自定义控件提供设计时支持。 当开发人员使用控件选择这里控件时,将在ide编辑器的属性中显示类别和说明文本。

已经通过web服务捕获了控件所需的值,惟一要做的就是在页面上实际呈现控件。

用来呈现控件的代码相当简单;HtmlTextWriter 用于定义表并设置它的特性( 这里示例中的单元格填充)。表的每一行都包含一个单元格,其中包含单元格,并添加了值本身。 一旦所有数据都写入到 table 中,就会呈现结束标记,并且控件完成。

定义 table 定义的每个部分,空行将 table 呈现代码分解为特定的部分。 如果你遵循注释和断点,你应该看到如何轻松地呈现控件。 以下进程基本上是定义一行,添加单元格,向单元格添加内容,关闭单元格,关闭行。

自然,你可以更改 table的配置,或者通过在 HtmlTextWriter 中定义的HTML定义来删除从web服务返回的数据。 通过使用 HtmlTextWriter,重写 RenderContents 子例程并在这个子例程中格式化 HTML。

如果希望使控件更有用,则使用垂直布局或者水平布局选项构建它,并使用渲染器中的select语句lay在一行或者在下面的中执行 select case。 如果开发者指定( 1至 7 )的天数并使用这个值来确定在天气报告中显示多少天,那么这可能是好的。

#Region"Rendering" 
 ProtectedOverridesSub _
 RenderContents(ByVal output As HtmlTextWriter)
 ' the web service actually returns ' seven days, I am just using the ' first three days to make a 3 day' forecast but the additional days' could be added in a similar mannerTry' set padding and start the table output.AddStyleAttribute(HtmlTextWriterStyle.Padding, "3")
 output.RenderBeginTag(HtmlTextWriterTag.Table)
 ' display location information based on zip code' in first row of the table output.RenderBeginTag(HtmlTextWriterTag.Tr)
 output.RenderBeginTag(HtmlTextWriterTag.Td)
 output.Write("<b>Location: </b>" & _
 Wx.PlaceName.ToString() & "," & _
 Wx.StateCode.ToString() & "<br/>")
 output.Write("<b>Zip Code: </b>" & ZipCode & "<br/>")
 output.Write("<b>Lat/Long: </b>" & Wx.Latitude.ToString() & _
 "/" & Wx.Longitude.ToString() & "<br/>")
 output.RenderEndTag()
 output.RenderEndTag()
 ' display highs and lows for day 1 output.RenderBeginTag(HtmlTextWriterTag.Tr)
 output.RenderBeginTag(HtmlTextWriterTag.Td)
 output.Write("<hr/>")
 output.Write("<b> Day: </b>" & _
 WxDetails(0).Day.ToString() & _
 "<br/>")
 output.Write("<b> High/Low: </b>" & _
 WxDetails(0).MaxTemperatureF.ToString() & _
 "/" & WxDetails(0).MinTemperatureF.ToString() & _
 "<br/><br/>")
 output.RenderEndTag()
 output.RenderEndTag()
 ' get weather service image and add it to control output.AddAttribute(HtmlTextWriterAttribute.Align, "center")
 output.RenderBeginTag(HtmlTextWriterTag.Tr)
 output.RenderBeginTag(HtmlTextWriterTag.Td)
 Dim img AsNew Image()
 img.ImageUrl = WxDetails(0).WeatherImage.ToString()
 img.BorderStyle = WebControls.BorderStyle.Inset
 img.BorderWidth = 2 img.RenderControl(output)
 output.RenderEndTag()
 output.RenderEndTag()
 ' display highs and lows for day 2 output.RenderBeginTag(HtmlTextWriterTag.Tr)
 output.RenderBeginTag(HtmlTextWriterTag.Td)
 output.Write("<hr/>")
 output.Write("<b>Day: </b>" & _
 WxDetails(1).Day.ToString() & _
 "<br/>")
 output.Write("&;lt;b>High/Low: </b>" & _
 WxDetails(1).MaxTemperatureF.ToString() & _
 "/" & WxDetails(1).MinTemperatureF.ToString() & _
 "<br/><br/>")
 output.RenderEndTag()
 output.RenderEndTag()
 ' get weather service image and add it to control output.AddAttribute(HtmlTextWriterAttribute.Align, "center")
 output.RenderBeginTag(HtmlTextWriterTag.Tr)
 output.RenderBeginTag(HtmlTextWriterTag.Td)
 Dim img2 AsNew Image()
 img2.ImageUrl = WxDetails(1).WeatherImage.ToString()
 img2.BorderStyle = WebControls.BorderStyle.Inset
 img2.BorderWidth = 2 img2.RenderControl(output)
 output.RenderEndTag()
 output.RenderEndTag()
 ' display highs and lows for day 3 output.RenderBeginTag(HtmlTextWriterTag.Tr)
 output.RenderBeginTag(HtmlTextWriterTag.Td)
 output.Write("<hr/>")
 output.Write("<b>Day: </b>" & _
 WxDetails(2).Day.ToString() & _
 "<br/>")
 output.Write("<b>High/Low: </b>" & _
 WxDetails(2).MaxTemperatureF.ToString() & _
 "/" & WxDetails(2).MinTemperatureF.ToString() & _
 "<br/><br/>")
 output.RenderEndTag()
 output.RenderEndTag()
 ' get weather service image and add it to control output.AddAttribute(HtmlTextWriterAttribute.Align, "center")
 output.RenderBeginTag(HtmlTextWriterTag.Tr)
 output.RenderBeginTag(HtmlTextWriterTag.Td)
 Dim img3 AsNew Image()
 img3.ImageUrl = WxDetails(2).WeatherImage.ToString()
 img3.BorderStyle = WebControls.BorderStyle.Inset
 img3.BorderWidth = 2 img3.RenderControl(output)
 output.Write("<br/><br/>")
 output.RenderEndTag()
 output.RenderEndTag()
 ' close the table output.RenderEndTag()
 Catch' the control will not render without contacting the web service' so just display text if the data is unavailable or the web ' service web method has not be evoked output.Write("Weather Report Control")
 EndTryEndSub#End Region

代码:站点页面的演示默认

演示站点中包含的Default.aspx 页面只为控件提供一个测试容器。 页面包含一个 table,这样左手列中存在三行,右手列包含一行( 三个合并单元格)。 在右栏中,添加了一个标签并设置为显示"你的3-day 预测"。 自定义预测控件的单个副本在标签下被删除。 控制代码属性的zip设置为" 36201",这是在Alabama州的有效邮政编码。

在 table的左侧,第一个单元格包含一个文本框,用于更新应用于自定义控件的zip代码。 单元格还包含用于打开服务代码查找器网站的美国邮政邮政编码的超链接。 在中间单元格中删除了日历控件,但除了显示日期之外,它不提供任何有用的用途。 左侧列中的底部单元格为空。

图 3: 在设计时设置预测控制属性

在 Default.aspx 页面中没有许多代码,用于更新邮政编码的按钮单击事件处理程序是唯一的。 代码在检查文本内容的同时,检查是否存在字母,如果通过检查,则更新控件代码属性的自定义 zip,并触发控件的public"getweather"子程序。 修改邮政编码属性后,GetWeather 子例程将强制更新控制信息的自定义天气,并在控件中显示新数据。

处理程序的click事件代码如下所示:

ProtectedSub Button1_Click(ByVal sender AsObject, _
 ByVal e As System.EventArgs) Handles Button1.Click
 IfNotString.IsNullOrEmpty(txtZipCode.Text.ToString()) ThenTryDim chr() AsChar = txtZipCode.Text.ToCharArray()
 Dim iLoop AsIntegerFor iLoop = 0To chr.Length - 1IfChar.IsLetter(chr(iLoop)) Then txtZipCode.Text = "INVALID"ExitSubEndIfNext Forecast1.ZipCode = txtZipCode.Text
 Forecast1.GetWeather(txtZipCode.Text)
 Catch ex As Exception
 txtZipCode.Text = "ERROR"EndTryEndIfEndSub

摘要

这里项目旨在描述一个有用的。易于构建的自定义控件。 虽然这里演示仅限于描述 Forecast 自定义控件,但这里应用的方法将适用于各种其他自定义控件。


相关文章