扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
ASP.NET 2.0并没有抛弃1.1版本中的任何现有控件,而是增加了一组新的控件;同时还引入了若干新的控件开发技术。本系列文章将对这些内容展开全面探讨。
一、 引言
到目前为止,你可能已经了解了大量的ASP.NET 2.0新特征—母版页面,主题,提供者,等等……所有这样内容都相当精彩;但是,你是否了解到有关定制Web控件开发方面的重大变化?这正是我在本文中所想讨论的。如果你已经从事于控件开发,那么,我想本文所描述的ASP.NET 2.0中的新的改进特征会立即应用于你的控件开发中。
首先应该注意的是,你以前使用ASP.NET 1.1(或1.0)开发的所有Web控件在2.0版本下将继续良好运行—微软并没有破坏你的现有代码。在本文中,我将向你介绍的所有相关内容,包括许多新的令人激动的技术,所有这些你都可以添加到现有控件或在新的控件环境中使用。
作者注:本文假定你对定制Web控件开发已经有一个基本了解。在本文中,我以一个增强版本的EmailContact控件为例对ASP.NET 2.0中的Web控件改进技术作全面探讨。
二、 改进
表格1描述了ASP.NET 2.0在定制Web控件开发方面所作的大部分的重大改进。在本系列文章中,我将对这些特征展开逐一讨论。
表格1:ASP.NET 2.0 Web控件改进功能。
三、 增强EmailContact Web控件
本文中的定制EmailContact Web控件(参考图1)允许在你的站点中加入一个“contact us”表单,它具有完整的电子邮件功能。在本文中,我将使用该功能增强这一控件。
图1.缺省状态下的EmailContact控件
四、 一个新的基类
以前,开发者都是从WebControl类派生他们的可视化Web控件。我之所以在此使用了“可视化”一词是因为,典型情况上,没有在浏览器中生成任何内容的控件都是派生自Control类。这一点并没有改变—你应该继续使用该Control类来派生任何这样的非可视化控件—它们执行不可见功能或在浏览器中生成除可视化HTML内容之外的任何其它内容。而且,在开发可视化Web控件时,你还应该继续使用WebControl类。然而,我们所开发的大多数复合控件都是为了利用现有控件的功能。在这种情况下,你应该总是从WebControl类进行派生,但是你还要记住另外一些有关细节—否则的话,有可能导致许多问题。
复合控件必须实现INamingContainer接口,并且需要包括在你的控件类中。这个接口能够确保在你的控件及其可以生成的整个控件层次中的所有的HTML标签中都具有唯一的标签命名。当你在单个页面上存在多个相同类型的复合控件的情况下,这是相当关键的。在这样的情况下,你需要确保任何生成的子元素都具有唯一的名称。忘记实现该接口能够导致各种问题的出现。
在ASP.NET 2.0以前,复合控件开发者还需要记住在一个控件的Render方法中调用EnsureChildControls。在我以前的文章中曾经向你介绍如何重载该Render方法并且在调用基类的Render方法前调用这个方法。要使控件在Visual Studio设计时刻正确生成这一步是必要的;否则,有可能带来许多不便。
上面两个步骤在复合控件开发中如此普遍,以致于许多开发者往往都会构建一个包括这两个细节的基类,然后从该基类下派生他们所有的新的复合控件。作为代替,ASP.NET 2.0提供了(更准确地说是“名字为”)CompositeControl。借助于这个类来构建你的复合控件,你就不必再记住实现INamingContainer或从Render方法中执行一个EnsureChildControls调用了。
另外,还存在其它一些新的基类,例如用于数据绑定的控件等,在此不再赘述。全面探讨ASP.NET 2.0中的Web控件改进技术之ControlState篇(二)
我的观点是:ViewState有可能成为你最好的朋友,也有可能成为你最坏的敌人—这要依赖于你使用它的方式来决定。如果你在以前曾经使用过ViewState,那么,你肯定会喜欢新的ControlState。
关于ViewState的最令人头痛的问题之一就是,它的“all-or-nothing”状态管理方法。页面开发者可以很容易地决定在任何控件级,页面级或在整个站点级(经由web.config)上关闭ViewState。事实上,如果你在整个站点级上通过web.config关闭ViewState的话,那么,你不妨猜测一下你还能够在其它什么地方关闭它?答案是:还可以在machine.config中实现—在此情况下,它能够影响到同一服务器上的所有站点。如果一个页面开发者决定关掉在ViewState中实现状态管理的能力,那么,你的控件生成有可能出现部分不可用,或更有甚者—完全不可用。
为此,在新版本中,微软创建了ControlState—旨在解决这一问题。页面开发者不能关掉ControlState,因此使用它进行属性选择更为安全。
使用ControlState与使用ViewState几乎完全一致。然而,ControlState并没有提供象ViewState这样的一个变量,而是提供了称为SaveControlState和LoadControlState的方法以便于你的控件能够进行重载。这些方法与SaveViewState和LoadViewState方法的工作原理完全一致。
因为ControlState在属性语句中没有提供一个相应的变量,所以,你必须借助于ASP.NET开发者以前在他们的对象中所使用的成员变量(属性语句)来实现相同的功能。
Protected _MailServer As String = "First name:" Public Property MailServer() As String Get Return _ MailServer End Get Set(ByVal value As String) _MailServer = value End Set End Property |
然而,因为我使用了一个标准的成员变量来保存值,所以我需要一种方法以便把数据存储在ControlState中—这正是前面提到的方法“登场”的原因。就象在它们相应的ViewState方法中那样,ASP.NET将在页面生命周期内调用这两个方法。其中,SaveViewState方法返回一个将被持久存储的对象类型。通过返回一个对象数组,这个方法可以存储多个值。并且,就象发生在SaveViewState方法中一样,也是使用数组的0下标元素来调用基类的SaveControlState方法。
Protected Overrides Function SaveControlState() As Object Dim state() As Object = New Object(2) {} state(0) = MyBase.SaveControlState() state(1) = _MailServer Return state End Function |
注意:LoadControlState方法以一个对象作为参数—这个对象是以前在SaveControlState中返回的一个对象。在这个方法中,我重新分配了成员变量—通过把该参数转换为一个对象数组,然后获得每个下标的值。与以前一样,我使用数组的0下标来调用基类的LoadControlState方法。
Protected Overrides Sub LoadControlState( _ ByVal savedState As Object) If savedState IsNot Nothing Then Dim state() As Object = CType(savedState, Object()) MyBase.LoadControlState(state(0)) _MailServer = CType(state(1), String) End If End Sub |
借助于这些方法来存储数据,在页面开发者关掉ViewState时,控件就不会出现前面那些麻烦。你可能对ControlState的存储位置感到惊讶;它对应于另一个生成到HTML页面中的隐藏的文本框。就象在ViewState情况下数据被存储在__ViewState隐藏文本框中类似,ASP.NET 2.0使用__ControlState隐藏文本框来存储ControlState数据。
遗憾的是,微软没有向开发者提供内在地使用ControlState的能力—就象在ViewState情况下那样。所以,为了ControlState使用,你需要注册你的控件。你可以重载控件的OnInit事件并且调用Page对象的RegisterRequiresControlState方法。
Protected Overrides Sub OnInit(ByVal e As System.EventArgs) MyBase.OnInit(e) If Page IsNot Nothing Then Page.RegisterRequiresControlState(Me) End If End Sub |
现在,你可以使用ControlState来存储你认为足够重要的数据—如果不把它存储起来,那么你的控件可能生成一些无用的内容。
记住,你在设计时刻对属性的修改将被硬编码到该控件的ASPX声明中,从而在相邻的再次回寄之间自动地存储。然而,如果表单上的一个行为改变了一个控件的属性,那么,这将会激活状态管理机制的使用。如果不把该属性存储在一个状态中,那么,在下一次回寄时它将恢复到“硬编码”状态。
现在,总的来看,我们应该把与外观相关的属性存储在ViewState中,而把与行为相关的属性存储在ControlState中。通过这种方式,如果一个页面开发者关掉ViewState,那么你的控件尽管可能看起来样子别扭,但是仍能正确工作。
全面探讨ASP.NET 2.0中的Web控件改进技术之灵敏标签篇(三)
当你最开始在Visual Studio 2005中使用Windows表单控件或是ASP.NET Web控件时,你首先会注意到,在许多控件右上角出现一个箭头形状的小玩意儿(见图2中的示例)。点击这个箭头会弹出一个小窗口,其中包含该控件的一些属性,还有一两个链接。微软设计这些灵敏标签是为了显示你需要操作的一些属性,其最终目的是为了使该控件在一个页面或表单上能够正确工作;并且你将注意到,它们比一个普通的快捷菜单更为精致。本节中我们讨论的内容既适用于Windows表单控件也适用于ASP.NET服务器控件。
图2.EmailContact控件的灵敏标签为了构建你自己的灵敏标签,你需要使用一个控件设计器类。事实上,你在另外其它一些问题上也会使用这个类。但是,在我详细讨论设计器类前,我想先创建一个ActionList类—这个类将定义我的灵敏标签中包含的元素。
一个ActionList类继承自System.ComponentModel.Design命名空间中的DesignerActionList类。但是,在详细讨论这个类之前,让我先来解释一下存在于灵敏标签中的四种类型的元素:category header,property mapping,action link以及information item。图2展示了我构建这个灵敏标签的目标。你能够从中看出我所指的这四种类型的元素吗?我把这个灵敏标签根据标题分为三类:“Appearance & Behavior”,“Support”和“Information”。其中,“Appearance & Behavior”分类中包含了两个属性:Mail Server和Pre-defined Display。这些实际上都是EmailContact控件本身的属性。“Support”分类包含两个激活某些类型的一个行为的链接,而“Information”分类仅用于显示信息。现在,有了这四种类型的元素,我将着手创建我的ActionList类。
我将创建一个称为EmailContactActionList的类,并且从DesignerActionList中加以派生。(你可以在本文源码列表1中看到完整的类)。我将创建一个构造器—它接收一个EmailContact实例作参数并且把它的范围扩大到一个称为ctlEmailContact的类级变量。后面,当我把代码添加到设计器类时,你将看到这个构造器的使用情况。现在,我已经建立了一个类级的对象,它包含我正在设计的Web控件的实例。
接下来,我将创建灵敏标签将显示的属性的“property mapping”。在图2中,你看到我已经在该灵敏标签中标出了两个属性:MailServer和PreDefinedDisplay。这些将分别映射到EmailContact控件的称为MailServer和PreDefinedDisplay的属性上。ActionList类中的属性映射将在get存取器中返回控件的属性,而在set存取器中设置控件的属性。然而,由于微软设计ActionList基础结构的方式决定了,你不能直接设置该控件的属性。而是,你必须使用反射机制来存取该控件的属性,然后再设置它的值。为了方便这一实现,我编写了一个称为GetControlProperty的方法,它能够返回一个PropertyDescriptor对象。这样以来,开发者就不需要再重复每一种属性映射下的反射编码。下面是一个属性映射看起来的样子。
Public Property MailServer() As String Get Return ctlEmailContact.MailServer End Get Set(ByVal value As String) GetControlProperty("MailServer"). _ SetValue(ctlEmailContact, value) End Set End Property |
接下来,我需要建立的是你在图2中所看到的链接:“About EmailContact”和一个到我自己的网站的链接。这些链接将执行我将在这个类中创建的方法。我的第一个方法名为ShowAboutBox,它显示一个Windows表单以用作我的控件的一个“关于”信息提示窗口。第二个方法称为LaunchWebSite,它执行一个对System.Diagnostics.Process.Start的调用以便在一个浏览器实例中启动我的网站。这两个方法的唯一的要求是:每一个签名都必须是一个“Sub”(在C#语言中相应于一个void函数)并且不带参数。
注意,在这个灵敏标签示例中仅显示了两个属性和两个链接,但是借助于我刚才所展示的技术,你完全可以提供你所需要的尽可以多的这些对象。然而,我建议:不要使用太多的信息来重载一个灵敏标签。记住,你仅想把信息放于此以便页面开发者立即使用,从而使得Web控件开发更具直观性。
现在,既然我已经创建了我的属性映射和行为方法,那么接下来,我将创建灵敏标签的内容。其中,DesignerActionList类提供一个称为GetSortedActionItems的重载函数。以后,一个设计器类将重载这个函数,并且它会返回一个DesignerActionItemCollection(定义于System.ComponentModel.Design命名空间)类型的对象。
这个属性重载的实现部分将创建一个新的DesignerActionItemCollection对象并且使用四个不同的类(DesignerActionHeaderItem,DesignerActionPropertyItem,DesignerActionMethodItem和DesignerActionTextItem)的实例来填充它。注意,这四个类都派生自抽象DesignerActionItem类。下面,我将同你逐个展开讨论。
Dim o_Items As DesignerActionItemCollection = _ New DesignerActionItemCollection |
o_Items.Add(New DesignerActionHeaderItem( _ "Appearance & Behavior")) |
为每一种分类创建准确的标题是相当重要的,这不仅是因为它作为在灵敏标签中作为该分类的头部相应的显示文本这一用途。早些时候,我创建了两个分别称为MailServer和PreDefinedDisplay的属性映射;现在我想把它们添加到灵敏标签中。为此,我将创建DesignerActionPropertyItem类的实例并且把它们添加到集合中。
o_Items.Add(New DesignerActionPropertyItem( _ "MailServer", "Mail Server", _ "Appearance & Behavior")) |
注意,该构造器接收三个参数:属性名,将出现在灵敏标签上的文本信息,以及相应类型的准确标题(在DesignerActionHeaderItem的实例中定义)。
接下来,我想以相同的方式把行为链接添加到灵敏标签。注意,也仅仅是在此时,我们使用了DesignerActionMethodItem类的实例。
o_Items.Add(New DesignerActionMethodItem( _ Me, "ShowAboutBox", "About EmailContact2", _ "Support", "Displays the about box.", True)) |
在此,构造器接收方法名,链接说明,类型文本以及一个用作链接的提示信息的描述等共四个参数。其中,第四个参数决定这个链接是否还出现在属性浏览器的底部。
最后,我将把信息项添加到灵敏标签中—这是使用DesignerActionTextItem类来实现的。
o_Items.Add(New DesignerActionTextItem( _ "ID: " & ctlEmailContact.ID, "Information")) |
在此,构造器仅接收要显示的文本和该文本要放置的类型。
列表1(见源码文件)中的最终代码展示了我要添加到这个集合中的所有项。当该方法完成时,它简单地返回这个集合。在后面一篇中,我们将讨论控件设计器类的问题。
全面探讨ASP.NET 2.0中的Web控件改进技术之控件设计与模板设计篇(四)
一、 控件设计器
控件设计器类派生自System.Web.UI.Design.WebControls.CompositeControlDesigner。该类通过控件类中声明的一个属性绑定到控件上:
DesignerAttribute(GetType(EmailContactDesigner))
在Web表单设计器中,它能够把控件的所有外观和行为特征呈现在用户面前。当页面开发者把一个Web控件拖动到Web表单上时,页面开发者可以通过各种交互方式取得控件的各种属性。这些属性将影响到页面开发者所看到的内容—不只是影响到控件本身,还包括一些更微妙的幕后元素(例如灵敏标签)。
实际上,控件设计器能够在设计时刻生成一种与运行时刻不同的输出结果。在有些情况下,一个控件在运行时刻可能没有任何可视化生成,但是却要求在设计时刻实现一些显示,以便更容易地操作它。这种情况的一个示例就是,ASP.NET 2.0中所提供的声明性数据源。这些控件提供了数据存储和缓冲功能,但是却没有可视化生成。然而,在设计时刻,它们表现为一个带有一些描述性文本的灰色窗口—出现在web表单设计界面上。另一个关于不同生成的例子是,有些控件不生成任何内容—除非它们被绑定到数据源。例如,当GridView(在1.1版本中是DataGrid) 带有数据时,它看上去十分正常;但当不存在要显示的数据行时,看上去什么东西也没有(或只显示为空的头部)。当你把一个这样的控件拖动到Web表单上时,控件往往使用几个具有示例性质的空数据行进行显示—这是由设计器类所提供的。 当Visual Studio需要决定在一个灵敏标签中显示的内容时,它存取设计器类的一个称为ActionLists的属性,并且使用它的结果来构建该灵敏标签。该ActionLists属性返回一个System.ComponentModel.Design命名空间中的DesignerActionListCollection类型的对象。在我的设计器类中,我将重载这个属性并且构建一个DesignerActionListCollection对象。我将返回的这个对象将在类范围上加以声明,并且检查ActionLists属性是否是一个“nothing”值。
Private o_ActionLists As _ DesignerActionListCollection |
控件设计器中的值都是被缓冲的,因此不需要被重复创建,以便使设计器更为有效地生成控件。
控件设计器类的一个重要特征是一个称为Component的成员。它是在控件设计器类所继承的基类中进行声明的,并且包含一个对实际的控件(设计器类被绑定到其上)的引用。我可以使用这个变量,并且把它转换成我的实际的控件类型—既然该变量被声明为object类型。
Dim ctlEmailContact As EmailContact = _ CType(Component,EmailContact) |
其结果是一个称为ctlEmailContact的对象,它包含一个这个类当前正在设计的实际控件的强类型实例。所以,我在这个对象上作的任何改变或执行的任何操作都将立即被反映到Web表单设计界面中,并呈现在页面开发者面前。
关于这个属性重载的其它方面的实现还包括,把我前面创建的ActionList类的一个实例添加到我在类级上创建的DesignerActionListCollection对象。
o_ActionLists.Add(New EmailContactActionList(ctlEmailContact))
你可能还记得我在EmailContactActionList类中创建的一个构造器,当时它接收EmailContact控件的一个实例。如你所见,我在此也使用了该构造器—把我设计的控件实例传递给它。
下面是控件设计器类用于构建灵敏标签的完整源码:
Private o_ActionLists As DesignerActionListCollection Public Overrides ReadOnly Property ActionLists() As _ System.ComponentModel.Design.DesignerActionListCollection Get If o_ActionLists Is Nothing Then o_ActionLists = New DesignerActionListCollection Dim ctlEmailContact As EmailContact2 = _ CType(Component, EmailContact2) o_ActionLists.Add( _ New EmailContactActionList(ctlEmailContact)) End If Return o_ActionLists End Get End Property |
在这个示例中,我仅创建了一个ActionList类,使用行为列表项填充它,并且把该类添加到将被返回的DesignerActionListCollection类—这是通过重载控件设计器的ActionLists属性来实现的。其实,我完全可以据实际需要创建许多ActionList类,并且简单地把它们添加到ActionLists属性集合即可。如果我想在逻辑上组织大量的灵敏标签项—为了在多个控件中重用它们时,这是很有用的。至于决定为何以及何时这样做,则要依赖于实际来决定。现在,在我编译完这个控件并把它拖动到一个表单上时,我将看到一个小箭头出现在其右上角—点击它将显示你在图2中所看到的内容。在此,改变任何其中一个属性都与在属性浏览器中改变完全一致。点击相应的链接将执行在EmailContactActionList类的方法中定义的行为。
关于该控件,我们就讨论这些内容。记住一点:不要把暂时不需要的属性添加到一个灵敏标签中。
二、 模板设计时刻编辑
在以前的文章中,我曾经介绍过如何在你的控件中添加模板能力。在此,我仅简单地涉及其中一点,因为它与这里的讨论有一些关系—我指的是从Web表单设计界面上编辑模板内容的能力—在以前的ASP.NET 1.x时代这是不容易实现的。
模板设计时刻编辑功能出现在例如GridView这样的控件中—你可以把该控件置于“模板编辑”模式,然后只需把其它控件拖动到该模板区域即可。如果没有这种方便的话,页面开发者必须切换到ASPX视图并象下面这样手工地创建模板内容:
<dnd:EmailContact ID="ctl1" runat="server"> <HeaderTemplate> <asp:Label ID="lbl1" runat="server" Text="Label" /> <asp:Textbox ID="txt1" runat="server"/> </HeaderTemplate> <FooterTemplate> <asp:LinkButton ID="lnk1" runat="server" Text="LinkButton" /> </asp:LinkButton> <asp:DropdownList ID ="ddl1" runat="server" /> </FooterTemplate> </dnd:EmailContact> |
尽管这也并不是太糟糕,但是使页面开发者使用设计器界面进行设计效果会更好一些。
为了把模板编辑能力添加到一个控件上,你必须重载控件设计器类的Initialize方法,并且设置一个标志以通知设计器你想支持模板编辑功能。
Public Overrides Sub Initialize( _ ByVal Component As IComponent) MyBase.Initialize(Component) SetViewFlags(ViewFlags.TemplateEditing, True) End Sub |
注意在此,我对基类方法进行了调用以确保我不取消自己不想实现的内容。这个调用通知设计器它将支持模板编辑功能,但是你仍然需要对编辑实现部分进行编程。
微软所使用的构建设计器的方式是,把模板分类到模板组中;这种情况下,在你的控件中将会存在许多模板。模板本身是在一个称为TemplateDefinition的对象中定义的;而TemplateGroup对象包含一个或多个这些定义对象。TemplateGroup对象包含在一个TemplateGroupCollection类型的对象中;因此,正是在这里(TemplateGroupCollection类型的对象中),设计器类将在类级上声明一个这种类型的变量。就象在灵敏标签情况下一样,基础结构负责缓存这个对象—这正是我在一个类级范围上声明它的原因。
Private o_TemplateGroups As TemplateGroupCollection = Nothing |
Public Overrides ReadOnly Property TemplateGroups() As TemplateGroupCollection Get If o_TemplateGroups Is Nothing Then ... End If Return o_TemplateGroups End Get End Property |
在这个属性重载中,我将构建Visual Studio使用的TemplateGroupCollection。属性中的“Is Nothing”检查有助于阻止对这个对象不必要的重新构建。
首先我将实例化o_TemplateGroups对象。
o_TemplateGroups = New TemplateGroupCollection() |
现在,我需要使用我在“灵敏标签”一节中所讨论的组件变量来取得我设计的控件。
Dim ctl As EmailContact = CType(Component, EmailContact) |
稍后,我将使用这个变量。但是首先,我必须建立我要使用的相应于TemplateGroup和TemplateDefinition对象的两个对象变量。
Dim o_TemplateGroup As TemplateGroup Dim o_TemplateDefinition As TemplateDefinition |
现在我可以开始定义组和模板了。
o_TemplateGroup = New TemplateGroup("Surrounding Templates") |
文本“Surrounding Templates”将出现在分类标题中,适用于我放在这个组中的所有模板定义。
o_TemplateDefinition = New TemplateDefinition(Me, "Header Template", ctl,"HeaderTemplate",False) o_TemplateGroup.AddTemplateDefinition _ (o_TemplateDefinition) |
让我来详细分析一下该TemplateDefinition构造器中的参数。第一个参数是一个添加了模板编辑功能的设计器的实例—通常是Me;第二个参数是模板名—它将显示于一个快捷方式菜单或灵敏标签中。第三个参数是正在设计的控件—通过转换Component对象来得到它。第四个参数是控件中模板属性的名字。参数列表最后的Boolean参数被设置为False以便指定这个模板既接收服务器控件也接收HTML控件。如果把它设置为True则仅允许把服务器控件(常规Web控件)添加到模板上。你可能已经猜出,对于你想定义的每个模板和每个模板组,都要重复这一操作。最终结果是,我的o_TemplateGroups对象中填充了我的模板中定义的所有信息—而这正是我在这个属性中所返回的内容。
图3.在模板编辑方式的EmailContact控件
现在,我重新编译并转到我的测试页面。当我右击EmailContact控件时,我将看到“EditTemplates”被添加到快捷方式菜单中。子菜单下的列表将显示我在设计器类中所定义的模板组,而当我选择“Surrounding Templates”组时,我会看到类似图3所示的内容。现在,你可以看到我手工地添加到这两个模板中的控件;而事实上,我现在就可以把其它控件从工具箱直接拖动到其上。再次右击鼠标并选择“Edit Templates”将返回到标准控件视图并且在控件中显示该模板内容。
另外还注意,一个“Edit Templates”链接也被自动地添加到该控件的灵敏标签上。如果以前不存在一个灵敏标签,那么,当我把模板编辑代码添加到设计器类上时,它会自动地为我创建一个。
下面是完整的模板编辑代码:
Public Overrides Sub Initialize(ByVal Component As IComponent) MyBase.Initialize(Component) ' Turn on template editing SetViewFlags(ViewFlags.TemplateEditing, True) End Sub Private o_TemplateGroups As TemplateGroupCollection = Nothing Public Overrides ReadOnly Property TemplateGroups() _ As TemplateGroupCollection Get If o_TemplateGroups Is Nothing Then o_TemplateGroups = New TemplateGroupCollection() Dim o_TemplateGroup As TemplateGroup Dim o_TemplateDefinition As TemplateDefinition Dim ctl As EmailContact2 = CType(Component, _ EmailContact2) o_TemplateGroup = New TemplateGroup( _ "Surrounding Templates") o_TemplateDefinition = New TemplateDefinition( _ Me, "Header Template", ctl, "HeaderTemplate", True) o_TemplateGroup.AddTemplateDefinition( _ o_TemplateDefinition) o_TemplateDefinition = New TemplateDefinition( _ Me, "Footer Template", ctl, "FooterTemplate", True) o_TemplateGroup.AddTemplateDefinition( _ o_TemplateDefinition) o_TemplateGroups.Add(o_TemplateGroup) End If Return o_TemplateGroups End Get End Property |
一、 自动格式化
现在,让我们开始讨论本文中最有趣的内容。你是否曾把一个GridView拖动到一个表单上并且注意到在属性浏览器有一个标有“Auto Format…”的链接?当你点击它时,你会得到一个预定义格式的选择:例如Corporate,Elegant,Classic,等。事实上,随着ASP.NET 2.0发行的所有安全控件套件(Security Control Suite)都提供了这个特征。读完本节后,你一定会为在你的控件中提供这种功能的容易程度而感到吃惊。
首先,我要确定我想在控件中提供什么格式。我将通过创建三种格式来简化操作。其中的两个分别称为“Monochrome”和“Colorful”。第三个(实际上是第一个)称为“No Format”;当把它拖动到一个表单时,它能够把控件恢复到其原始状态。
我创建的每一种格式都需要它自己的继承自System.Web.UI.Design命名空间的DesignerAutoFormat类。因此,我先从一个称为ColorfulFormat的继承自DesignerAutoFormat的类开始。首先,我需要为这个类提供一个缺省的构造器;并且我将在其中调用基类的构造器,发送给它一个参数—格式名称(将出现在列表中)。
Public Sub New() MyBase.New("Colorful") End Sub |
接下来,我必须重载Apply方法。这个方法接收一个Control类型的参数。我的控件设计器类将调用这个方法,并且把我的控件实例发送到这个参数中。然后,我要把该参数转化成我的控件类型;这样以来,我就有一个可以使用的强类型引用了。
Public Overrides Sub Apply( _ ByVal control As System.Web.UI.Control) Dim ourControl As EmailContact2 = CType(control, EmailContact2) If ourControl IsNot Nothing Then ... End If End Sub |
现在,我要设置我需要的任何属性—这通常包括一些风格属性,但是它事实上能够包括我需要的一切。因此,在“IsNot Nothing”检查中,针对这个特定的格式,我只需简单地设置我想实现的任何风格属性。列表2展示了完整的列表。
ourControl.BackColor = Drawing.Color.Aquamarine ourControl.BorderStyle = BorderStyle.Double ourControl.BorderWidth = Unit.Pixel(2) ourControl.BorderColor = Drawing.Color.DarkRed ourControl.HeadingStyle.Font.Name = "arial" ourControl.HeadingStyle.Font.Bold = True ourControl.HeadingStyle.Font.Size = FontUnit.Large |
最后,我必须创建NoFormat类。这个类遵循与前两个相同的设计;但是,我不是把风格属性值设置成各种颜色及字体,而是在所有的风格属性上调用Reset方法。这可以把所有的风格值设置为它们的缺省状态。
顺便说一下,既然我的EmailContact控件派生自CompositeControl类,而它又派生自WebControl类;所以,我还可以在我的控件的类级上取得风格属性。这意味着:我可以拥有BackColor,ForeColor等属性,而且可以直接从我的控件中存取它们而不必通过一个属性来实现。然而,为了复位这些风格值,我不是直接从我的控件类取得一个Reset方法,而是由WebControl类为我提供了一个ControlStyle属性,它用作相应于所有的容器风格值的入口点。注意:在复位控件的外观时,我还把Height属性设置为一个具有400个像素的缺省值。下面是完整的类:
Public Class NoFormat Inherits DesignerAutoFormat Public Sub New() MyBase.New("No Format") End Sub Public Overrides Sub Apply(ByVal control _ As System.Web.UI.Control) Dim ourControl As EmailContact2 = CType(control, _ EmailContact2) If ourControl IsNot Nothing Then ourControl.ControlStyle.Reset() ourControl.HeadingStyle.Reset() ourControl.CaptionStyle.Reset() ourControl.FieldStyle.Reset() ourControl.ReadonlyFieldStyle.Reset() ourControl.ButtonStyle.Reset() ourControl.Height = Unit.Pixel(400) End If End Sub End Class |
现在,既然我已经创建了我想实现的所有格式类,那么,接下来,我需要对它们做一些实际的操作。为此,我将再转回到控件设计器类—实现一些重载。我需要重载的属性称为AutoFormats,它返回一个System.Web.UI.Design命名空间中的DesignerAutoFormatCollection类型的对象。
就象在灵敏标签和模板编辑部分一样,我将实例化的对象(为了通过属性返回之)是在类级上声明的,因为ASP.NET基础结构会负责对它进行缓冲处理。
Private o_AutoFormats As _ DesignerAutoFormatCollection |
然后,在属性重载实现中,我可以测试对象变量是否是一个null值。现在,我们只需简单地使用我以前创建的每一个格式类的实例来填充o_AutoFormats集合对象。
Public Overrides ReadOnly Property AutoFormats() _ As DesignerAutoFormatCollection Get If o_AutoFormats Is Nothing Then o_AutoFormats = New DesignerAutoFormatCollection With o_AutoFormats .Add(New NoFormat) .Add(New MonochromeFormat) .Add(New ColorfulFormat) End With End If Return o_AutoFormats End Get End Property |
如果我点击任何一个链接,我将看到如图4所示的内容。选择列表中的任何一种格式从而在预览窗口中改变它;然后点击OK把此设置提交给Web表单设计界面下的控件。
图4.自动格式化屏幕
现在,既然你已经了解了如何进行格式化,那么接下来,你应该学习何时以及为什么进行格式化。
我仿佛听到CSS爱好者正在对本文大声叫喊。其实,我本人就是一个“层叠式样表(CSS)”迷,并在我所有的站点中使用它们。自动格式化特征在有些情况下(例如控件组)是非常有用的。例如,我们不妨考虑微软的安全控件套件(Security Control Suite)。从中,你会看到七种Web控件可用于一个站点中以为页面添加认证功能。其中,每一种控件都提供了自动格式化功能,并且每一个控件都显示一样的列表用于从中选择一个格式—这是相当不错的功能。
试想一下我们今天已经实现的一些流行的可视化效果:例如Outlook工具栏中的许多风格,各种TreeView控件,菜单和工具栏,等。你完全可以把这其中的许多特征集成到几乎任何站点的设计风格中。在这种情况下,自动格式化是一种相当有用的工具。
现在请记住,在每一个格式类中,我把风格值改变为我的一些风格属性。如果你在Web表单中应用这些格式中的任一个,那么,你将会看到这些风格值确实在属性浏览器中改变了。如果我想(尽管我不会选择)这样做的话,那么我可以修改style属性的CssClass值,并且把一个风格表类指派给它们。这当然可以顺利地工作,但是之后,我需要同我的控件一起发布该CSS文件,并且还要确保页面链接到它。
如果我能够在我的控件中使用这些资源文件而不必随同控件的DLL文件一起发行它们,不是相当酷吗?好,下面我们来讨论本文的最后一个话题—Web资源。
一、 Web资源
Web资源是被编译到你的控件DLL中的一些嵌入式文件。Windows表单控件开发者很久以来就拥有这种能力,只是到现在它才被应用于Web领域。让我们想象开发一个依赖于某些图像才能正确生成的控件的情形。只是简单地发布该控件相应的DLL文件而不必考虑单独发布外部图像文件,这是特别有用的。分析一下微软提供的新的Tree Web控件,那么你就会发现这一特征。在此,图像文件是讨论使用Web资源的最佳候选,尽管我们还能够把它们使用于JScript文件中。
为了说明这一问题,我想把一个邮箱图像添加到我的EmailContact控件标题的左边。你可能已经注意到,在图4中“CONTACT US”标题文字的左边已经存在一个空图像。为此,我是通过简单地创建一个Image子控件并且把它添加到控件层次中的适当位置来实现的。事实上,我还创建了一个称为ShowMailIcon的属性以允许页面开发者隐藏/显示图像。使用常规方法就能创建一个HeadingImageUrl字符串属性,并且在图像控件的ImageUrl属性中设置它的值。这将允许页面开发者把这个图像设置为他所希望的任何内容。我同意这一方法,而我在这个控件中就使用了这种方法。然而,我更深入了一步。如果HeadingImageUrl属性不是空的,那么我使用它填充图像控件的ImageUrl属性(如前所述);但是如果该属性是空的,那么我要实现一些更酷的内容。
在我的Web控件工程中,我有一个称为mailbox.gif的邮箱图像。我将把图像的BuildAction属性设置为EmbeddedResource(注意,我可以通过属性浏览器来实现这一点)。
接下来,我需要存取我的工程的AssemblyInfo.vb文件。在ASP.NET 1.1中,这个文件位于我的工程的根文件夹下,但是在ASP.NET 2.0中,它位于我的工程文件夹下。不仅如此,我还必须点击属性浏览器顶部的“Show All Files”按钮存取这个文件。在AssemblyInfo.vb文件的底部,我需要添加下列语句:
<Assembly: WebResource("mailbox.gif","image/gif")> |
这一句把该嵌入式文件标识为一个可用的Web资源,以便于后面的提取操作。
为了提取该文件,我使用了Page.ClientScript对象的GetWebResourceUrl方法。如前所述,我想使页面开发者能够使用我自己的属性重载图像;因此我以如下方式进行提取:
If Me.HeadingImageUrl <> "" Then imgMail.ImageUrl = Me.HeadingImageUrl Else imgMail.ImageUrl = Page.ClientScript.GetWebResourceUrl( _ Me.GetType(), "mailbox.gif") End If |
这正是我所喜爱的新的Web控件特征,因为我往往不时地在一些地方使用小图像来修饰我的控件。现在,我能够嵌入它们,并且只需要我的控件的DLL文件。
测试该控件将显示如图5所示的结果。
图5.带有嵌入式图像的最终完成后的控件
该Web表单使用一个HTTP处理器来检索图像并且把它生成到浏览器。显然,这种使用可能性远远不止此。
二、 总结
我希望你喜欢本系列文章所介绍的内容。其实,ASP.NET 2.0在Web开发方面加入了许多酷的内容,例如引入了母板页面,主题,数据源,以及其它优秀特征。事实上,你也可以把回调(一种新的页面特征)嵌入到控件中,从而为它们加入AJAX功能以实现更好的响应时间并产生一种更为丰富的客户端体验。遗憾的是,有关这一方面的内容已经非本文所及。在本文中所介绍的新的控件开发特征当前尚不多见;当然,这也是我写本文的原因。如你所见,这其中的大多数内容都与设计时刻体验相关;但是,我一直认为,提高控件的直观性与使之有用且能够实现既定功能一样重要。如果不容易使用,那么你甚至无法全面地使用该控件所提供的功能。
濠电姷鏁告慨鐑藉极閸涘﹥鍙忛柣鎴f閺嬩線鏌涘☉姗堟敾闁告瑥绻橀弻锝夊箣閿濆棭妫勯梺鍝勵儎缁舵岸寮诲☉妯锋婵鐗婇弫楣冩⒑閸涘﹦鎳冪紒缁橈耿瀵鏁愭径濠勵吅濠电姴鐏氶崝鏍礊濡ゅ懏鈷戦梺顐ゅ仜閼活垱鏅堕鈧弻娑欑節閸屾稖纭€缂備緡鍠栭澶愮嵁閹烘妫橀柛婵嗗婢规洟姊洪幐搴g畵缂併劏鍋愰懞杈ㄧ鐎n偆鍘遍梺鍝勫暞閹搁箖鎮炬潏銊d簻妞ゅ繐瀚弳锝呪攽閳ュ磭鍩g€规洖宕灃闁逞屽墮宀e潡骞嬮敂瑙f嫼缂備礁顑嗛娆撳磿閹扮増鐓欓柣鐔哄閸犳ḿ鈧鍠涢褔鍩ユ径鎰潊闁炽儱鍘栫花濠氭⒒閸屾瑧顦﹂柣蹇旂箞椤㈡牠宕ㄩ缁㈡祫闂佸湱铏庨崰妤呭煕閹寸姷纾兼い鏍ㄧ⊕缁€鍐煛婢跺﹦绉洪柡灞剧〒閳ь剨缍嗛崑鍛焊椤撶喆浜滄い蹇撳閺嗭絽鈹戦垾宕囧煟鐎规洖宕灃闁逞屽墮宀e潡骞嬮敂瑙f嫼缂備礁顑嗛娆撳磿閹扮増鐓欑紒瀣仢閳锋梹淇婇崣澶婂妤犵偞锕㈤獮鍥ㄦ媴閸涘﹤鈧垶姊绘担鍛婂暈缂侇喖鐭傚畷顖炲箮閽樺袝濡炪倖鍔忛幊锟犲籍閸喎浜归梻鍌氱墛缁嬫劗鍒掗崼鏇熲拺闁告縿鍎卞▍蹇涙煕鐎n亶妯€闁诡喗锕㈤獮鎺懳旀担鍝勫箺闂備胶绮敋鐎殿喖澧庣划姘跺锤濡や礁鈧爼鐓崶銊︹拻闁瑰啿鎳愮槐鎺楊敋閸℃瑧袦闂佽鍠楅悷鈺呭箖濠婂吘鐔兼煥鐎n亶浼栭梻浣藉吹閸犳劗鍒掓惔銏℃珷婵°倕鍟弳婊堟煙閻戞ɑ灏垫い鈺傚絻闇夐柣鎾虫捣閹界娀鏌i幘瀛樼闁哄瞼鍠栭獮鍡氼檨闁搞倗鍠愮换娑㈠矗婢跺鍞夐梺鍝勭灱閸犳牠銆佸▎鎾村癄濠㈣泛锕よ闂備胶绮幐鍫曞磹閺嶎厼桅闁告洦鍠氶悿鈧梺鍦亾濞兼瑥鈻嶅┑瀣拺鐟滅増甯楅弫杈ㄤ繆閻愯埖顥夋い顐㈢箲缁绘繂顫濋鍌︾床婵犳鍠楅敋鐎规洦鍓熻矾闁逞屽墴濮婄粯鎷呴崨濠傛殘濡炪們鍔屽Λ妤冨弲闂佺粯妫冮ˉ鎾诲汲閿曗偓閳规垿宕掑┃鎾舵嚀閺侇噣姊绘笟鈧ḿ褔鏁嶈箛娑樼妞ゆ挾鍋涢崣濠傗攽閻樺灚鏆╁┑顔惧厴瀵偊宕ㄦ繝鍐ㄥ伎闂佸湱铏庨崰妤呭疾濠靛鐓忛柛顐g箖缁€宀勬煕鐎n偅灏い顐g箞閹剝鎯旈敍鍕綁闂佽姘﹂~澶娒洪埡鍐闁逞屽墰缁辨帡鎮╁畷鍥ㄥ垱閻庢鍣崳锝呯暦閹烘垟鍫柛娑卞櫘濞兼挸鈹戦悩鍨毄濠殿喚鍏樺顐﹀川婵犲啫寮块梺鍦檸閸犳牜澹曢崷顓犵=濞达綀鍋傞幋婵冩瀺闁绘ê纾粻楣冩煙鐎涙ḿ鎳冮柣蹇d邯閺岋綁骞樼€涙ḿ顦伴梺璇″枟椤ㄥ﹪寮幇鏉跨闁靛ǹ鍎洪悗鍐测攽閻樻鏆柍褜鍓濈亸娆撴儗濞嗘挻鐓涢悘鐐靛亾缁€瀣偓瑙勬礃閸庡ジ藝閸欏浜滈煫鍥风到楠炴﹢鏌嶈閸撴岸顢欓弽顓炵獥闁哄洨濮撮崹婵囩箾閸℃ê濮冪紒璇叉閹便劌鈹戦崱娆戝姼濠碘剝褰冪紞濠傤潖濞差亝鐒婚柣鎰蔼鐎氭澘顭胯閸ㄥ爼骞冩禒瀣垫晬闁靛牆娲ㄩ惁鍫ユ倵濞堝灝鏋涙い顓犲厴楠炲啴濮€閵堝懐顦ч梺缁樻尭濞村嘲顬婇灏栨斀闁绘﹩鍠栭悘杈ㄧ箾婢跺娲撮柡浣稿暣婵$兘濡烽姀锛勪簴濠电姷鏁告慨鐢靛枈瀹ュ鐓曢柟杈鹃檮閻撴洘绻濋棃娑欘棞妞ゅ浚鍋婇弻锝堢疀濞戞鍠氶梺鍝勬湰閻╊垶骞冮埡浣烘殾闁搞儜鈧幏鐗堜繆閵堝洤啸闁稿鐩畷顖烆敃閿斿搫浜兼繛鏉戝悑濞兼瑩鏌嬮崶銊х瘈闂傚牊绋撴晶鏇燁殽閻愭潙濮嶆慨濠勭帛閹峰懘宕ㄩ棃娑氱Ш鐎殿喚鏁婚、妤呭磼濠婂懐鍘梻浣筋潐閸庡磭绮诲鍡欘洸鐟滅増甯楅崐鐢告煥濠靛棝顎楅柡瀣枛閺岋綁骞樼捄鐑樼亪濡ょ姷鍋為悧鏇″絹濡炪倖宸婚崑鎾绘煃瑜滈崗娆撳磹閺囩偟骞撻柛褎顨呯粻娑欍亜閹捐泛啸妞ゆ梹娲熷娲川婵犲嫭鍣у銈冨劘閸ㄤ粙銆侀弮鍫濋唶闁绘棁娓归幃锝嗙節閻㈤潧鈻堟繛浣冲洦鍋嬮煫鍥ㄧ⊕閸庢绻涢崱妯诲鞍闁稿缍侀弻鐔碱敇閻旈鐟ㄦ繝寰枫倕袚缂佺粯鐩畷濂稿Ψ瑜忛弳顐⑩攽椤旂》鏀绘俊鐐舵閻e嘲饪伴崼婵堫唽闂佺懓鎼粔鍫曞礄鐟欏嫮绡€闁汇垽娼ф禒婊呪偓娈垮枛閻栧ジ骞冭閹晝鎷犻懠顒傛毇闂備胶鍋ㄩ崕鏌ュ几閻撳宫锝夊醇閵夛妇鍘棅顐㈡储閸庡磭澹曢崸妤佺厱婵せ鍋撳ù婊冪埣瀵鏁愰崼銏㈡澑闂佸搫娲ㄩ崑妯煎垝閼哥數绡€闁冲皝鍋撻柛灞剧矌閻撴捇姊虹拠鈥崇仩闁活剙銈搁崺鈧い鎺戯功缁夌敻鏌涚€n亝顥犵紒顔剧帛閵堬綁宕橀埡鍐ㄥ箞婵$偑鍊栭崝鎴﹀磹閺囥垹鍑犻柟杈鹃檮閻撴洖鈹戦悩鎻掓殭濠殿喖鐗撻弻鐔哥瑹閸喖顬夌紓浣虹帛缁诲牆鐣烽悢纰辨晣闁绘劖顔栭崑褔姊婚崒娆掑厡闁硅櫕鎹囧畷鏌ュ蓟閵夈儳鐤囬梺褰掑亰閸犳牠宕瑰┑瀣厽闁靛繈鍩勯弳顖炴煕鐎n偅宕岄柡浣瑰姈閹柨鈹戦崼婵嗘瘓闂傚倷妞掔槐顔惧緤婵傜ǹ纭€闁告劕妯婂ḿ鏍磽娴h偂鎴炲垔閹绢喗鍋℃繛鍡楃箰椤忊晛霉閻橆偅娅婃慨濠冩そ瀹曘劍绻濋崘顏勫汲婵$偑鍊栭崹鐢杆囬鐐村仼闁绘垼濮ら弲鎼佹煟濡灝鐨烘い锔哄姂濮婃椽鎳栭埞鐐珱闂佸憡鎸婚懝楣冨煝閹炬番鍋呴柛鎰ㄦ杹閹锋椽姊婚崒姘卞缂佸鎸剧划濠氭倷閻戞ḿ鍘辨繝鐢靛Т閸燁垳绮堢€n兘鍋撶憴鍕闁挎洏鍨藉畷娲焵椤掍降浜滈柟鍝勬娴滄儳顪冮妶搴濈盎闁哥喎鐡ㄦ穱濠囧醇閺囩偛鑰垮┑掳鍊愰崑鎾淬亜椤愩垺鍠樻慨濠呮缁瑩宕稿Δ濞惧亾濡ゅ啠鍋撶憴鍕闁告挾鍠栭獮鍡涘礃椤曞懏鏅㈤梺鍛婃处閸忔﹢骞忔繝姘拺缂佸瀵у﹢浼存煟閻旀繂娲ょ粈澶屸偓骞垮劚椤︿即宕愰悽鐢电<婵°倓鑳堕埥澶愭煙閾忣偄濮嶉柟顖氳嫰閳诲酣骞樼€电ǹ骞嶉梺璇叉捣閺佸憡鐏欓悶姘ュ劦濮婅櫣绮欏▎鎯у壉闂佺懓鎲¢幃鍌炴晲閻愭祴鏀介悗锝庡亜娴滄鏌熼懝鐗堝涧缂佽鲸娲熼幆鍫ュ礋椤栨稓鍘介柟鍏肩暘閸娿倕岣块幇顓犵闁告瑥顦悘瀵糕偓瑙勬穿缁绘繂鐣峰鈧幊鐘活敆娴h鍟庨梻鍌欑閹诧繝銆冮崼銉ョ9闁挎繂顦伴崑鍕煕韫囨挾姣為柟宄扮秺濮婇缚銇愰幒鎴滃枈闂佸摜濮甸懝楣冨煝閺冨牆閿ゆ俊銈勮閹峰姊虹粙鎸庢拱闁荤啙鍛幓闁哄啠鍋撶紒缁樼⊕閹峰懘宕橀崣澶婎槱闂佺ǹ顑呴澶愬蓟濞戙垹鐒洪柛鎰典簴濡插牏绱撴担鍝勑ュ┑鐐╁亾濡ょ姷鍋為悧鏇″絹濡炪倖宸婚崑鎾绘煟韫囷絼閭柡灞剧☉閳诲氦绠涢弴鐙€鍞归梻渚€娼уú銈団偓姘嵆閻涱噣骞掑Δ鈧獮銏′繆閻愭潙鍔ゆい銉﹀哺濮婂宕掑▎鎴М闂佹眹鍊曞ú顓㈡晲閻愭潙绶為柟閭﹀墮閻庮參姊虹粔鍡楀濞堟棃鏌¢崟鈺佸姦闁哄本娲樺鍕幢濡崵褰呮俊銈囧Х閸嬫垿宕归悜妯尖攳濠电姴娲﹂崐鐑芥煙缂佹ê鍧婇柟绋垮暣濮婃椽宕ㄦ繝鍌滀紘濡炪値鍋勯ˇ閬嶅箲閵忕姭鏀介悗锝庡亜娴犳椽姊婚崒姘卞闁告巻鍋撻梺缁樺姉閸庛倝鎮¢弴銏$厪濠电姴绻樺顕€鏌曢崶銊х疄闁哄备鍓濋幏鍛村礈閹绘帒澹庨梻浣告惈閻瑩宕堕妸銉︻吋闂備線娼ч悧鍡涘箠瀹ュ應鏌︽い蹇撴噽缁犻箖鏌ㄥ┑鍡樺櫤闁瑰吋鍔欓弻銊╁即閵娿倗鍑规繛锝呮搐閿曨亜鐣锋總绋垮嵆闁绘劘灏欓悰鈺備繆閻愵亜鈧牠寮婚妸鈺佽Е閻庯綆鍣弫鍌炴煥閻斿搫校闁抽攱甯掗湁闁挎繂鎳忛崵鍫㈡喐閻楀牆淇柡浣稿閺屾稑鈽夊▎鎰▏缂佺偓鍎崇紞濠囧蓟濞戙垺鏅滈悹鍥ㄥ絻缁犳椽鎮楃憴鍕鐎殿喖澧庨幑銏犫槈閵忕姷顓哄┑鐐叉缁绘帗绂掗悡骞棃鎮╅棃娑楁澀闂佹悶鍔庨崕銈囩矚鏉堛劎绡€闁搞儴鍩栭弲顒€鈹戦悩鑼粵闁告梹娲栭埢鎾活敇閻樼數锛滈梺缁樺姦閸撴氨娆㈤懠顒傜<濠㈣泛锕︾粔铏光偓娈垮枛椤兘寮幇鏉垮耿婵☆垰鎼俊鎶芥⒒娓氣偓濞佳勵殽韫囨洖绶ゅù鐘茬懁婢跺ň鏀介柛鈾€鏅滅€靛矂姊洪棃娑氬缂佺粯鍔欓妴鍛搭敆閸曨剛鍘告繛杈剧悼閻℃棃宕靛▎鎰╀簻闁哄浂浜為幃濂告煙妞嬪骸孝妞ゆ柨绻橀、娆撳礂閻撳簶鍋撻鐐粹拻濞达絿枪椤ュ繘鏌涚€n偄娴€规洘鍨垮畷銊╁箹椤撶喐娅呴梻浣规偠閸庢椽宕滃璺虹厱闁圭儤鍤氳ぐ鎺撴櫜闁告侗鍠栭弳鍫ユ⒑閸濄儱鏋旈柛瀣ㄥ€濆濠氭偄閻撳海顔愭繛杈剧秬濞咃綁寮抽锔藉€甸悷娆忓缁€鍫濐熆瑜庨〃濠囩嵁閸℃稑绫嶉柛顐e焹閸嬫捇鏁冮崒姘鳖吅闂佺粯鍔曢悺銊╂偟閵娾晜鈷掗柛灞剧懅閸斿秹鎮楃粭娑樻噺瀹曟煡鏌涘畝鈧崐娑㈠炊閵娧屾祫闁诲函缍嗘禍婵嬫倵椤掑嫭鈷戠紒顖涙礀婢ф煡鏌曢崶銊х煉闁糕斁鍋撳銈嗗笂缁€浣虹箔閹烘挶浜滄い鎰剁悼缁犵偞銇勯姀鈽嗘畷缂佺粯绻堝畷鎺戭潩閸忓吋绁梻鍌氬€搁崐鐑芥倿閿曗偓椤啴宕稿Δ鈧崒銊ッ归悩宸剭闁逞屽墮閸熸潙鐣烽崡鐐╂瀻闁归偊鍓欑花銉︾節閻㈤潧浠﹂柛顭戝灦瀹曞綊宕烽鐘辩瑝婵犵數濮电喊宥夋偂濞戞﹩鐔嗛悹杞拌閸庡繘鏌h箛濠冩珚闁哄本鐩顒勫箚瑜嶇粊顔尖攽椤旂》榫氭繛鍜冪悼閸掓帒鈻庤箛濠冪€婚梺璇″瀻閸愵煈妫婇梻鍌氬€风粈浣革耿闁秴绠犻柟鎹愮М濞差亶鏁囬柣鎴濇濞堛劍绻濋悽闈浶g痪鏉跨Ч瀵煡寮婚妷锔惧幈濠电偞鍨佃ぐ澶岃姳閸忕浜滄い鎰╁灮瀛濋梺瀹狀潐閸ㄥ潡骞冨▎鎾崇煑濠㈣埖蓱閿涗線姊绘担鍛婂暈婵﹦鎳撶叅婵犲﹤瀚悵鍫曟煛閸ャ儱鐏╃紒鐙€鍣i弻銈夊箒閹烘垵濮夐梺褰掓敱濡炶棄顫忓ú顏勫窛濠电姴瀚悾鐢告煟鎼淬垹鍤柛妯恒偢閺佸啴濮€閵堝懐顓煎銈嗘煥婢т粙鏁嶅⿰鍫熺厽閹兼惌鍨崇粔鐢告煕鐎n亜顏柟顔斤耿楠炴﹢顢欓悾灞藉箞闂備礁鍟块幖顐﹀疮椤愶絿顩烽弶鍫厛濞堜粙鏌i幇顒佲枙闁稿孩妫冮弻鈩冩媴缁嬫寧娈婚梺绯曟杹閸嬫挸顪冮妶鍡楀潑闁稿鎸婚妵鍕棘鐠恒劎顔囬梺瀹狀潐閸ㄥ灝鐣烽崼鏇炍ㄩ柕鍫濇川濞夊潡姊婚崒娆戭槮闁圭⒈鍋勭叅闁靛ň鏅涚壕濠氭煟閹邦剚鎯堥梻鍌ゅ灡缁绘稑顔忛鑽ゅ嚬闂佺粯鎸搁崯鎾箖瑜版帒鐐婃い蹇撶Т濞堟繈姊洪崨濠冣拻闁哥姵鎸惧Σ鎰板箳閹惧绉堕梺闈涒康缁犳垹澹曢幎鑺ュ€甸悷娆忓缁€鍐偨椤栨稑娴柛鈹垮灪閹棃濡搁妷褜鍚呮繝鐢靛█濞佳兾涢銏″€甸柡澶嬪灍閺€浠嬫煥濞戞ê顏╁ù婊冦偢閺屾稒绻濋崘銊т紝閻庤娲樼换鍌炴偩濠靛绀嬫い鎰╁€楅弸鍐╃節濞堝灝鏋熼柕鍥ㄧ洴瀹曟垿骞橀幖顓燁啍闂佺粯鍔曞鍫曀夊⿰鍫熺厽闁挎繂妫涚粻鐐碘偓瑙勬礈閸犳牠銆侀弴銏犖ч煫鍥ㄦ礀缁ㄣ儵姊婚崒姘偓鐑芥嚄閸撲礁鍨濇い鏍仜缁€澶嬬箾閸℃绠樼紓鍌涙皑閹叉瓕绠涢弴鐐茬亰婵犵數濮村ú锕傚疾濠靛鐓曢悘鐐插⒔閵嗘帡鏌涘Ο鍏兼毈婵﹨娅g划娆戞崉閵娧屽晥闂備胶枪椤戝棝宕濆▎蹇e殨闁告劕妯婂ḿ銊╂煃瑜滈崜鐔奉嚕鐠囨祴妲堥柕蹇曞У椤ユ繈鏌i悩鍏呰埅闁告柨閰e畷婵嬵敍閻愮补鎷洪柣鐘叉礌閳ь剝娅曢悘鎾绘⒑缁嬫鍎嶉柛濠冩礋閹箖鎮块妯规睏闂佸湱鍎ょ换鍐疾濠靛鈷戠紓浣广€掔憴鍕洸妞ゆ帒瀚崕搴ㄥ箹濞n剙濡介柍閿嬪笒闇夐柨婵嗘噺閸熺偤鎮归幇鍓佺瘈闁哄本绋掗幆鏂库槈濡嘲浜炬繝闈涙閺嗭妇鎲搁悧鍫濈瑲闁稿鍔戦弻娑㈠箻閸愯尙楠囬梺鍝勬噺缁挸顫忓ú顏勭闁告瑥顦伴崕鎾绘⒑閻熸澘鏆辩紒缁樏悾鐑藉箛閺夊灝鐎銈嗗姧缁茶棄顕i崹顔规斀妞ゆ梻鐡斿▓鏃€淇婇锝庢畷闁哄懎澧庣槐鎺懳熼崷顓犵暰闂備礁婀辩划顖滄暜閻愮數鐭撴繛宸簼閻撴盯鎮橀悙闈涗壕缂佲偓鐎n兘鍋撶憴鍕闁稿骸銈歌棟闁告瑥顦禍婊堢叓閸ラ鍒版鐐达耿閺屽秷顧侀柛鎾村哺椤㈡瑩寮介鐐电崶闂佸搫娲ㄦ慨鎾垂濠靛洨绠鹃柛鈩兠慨鍐磼鐠囧弶顥為柟渚垮妼閳规垿宕卞▎鎴濆Ъ婵犵鍓濊ぐ鍐Χ缁嬫娼栨繛宸簼椤ュ牓鏌嶉崫鍕殶闁靛牏鍏樺铏圭矙閸ф鈧鐥紒銏犲箹閸楅亶鏌熼悧鍫熺凡缂佺姴顭烽幃妤€鈽夊▍顓т邯椤㈡捇骞橀崜浣猴紳婵炶揪绲藉﹢閬嶅煡婢跺浜滈柟瀛樼箖閸e綊鏌嶇紒妯诲磳妞ゃ垺锕㈤幃娆撳煛閸屾稒婢戦梻鍌欑閻ゅ洤螞閸曨倠娑樜旀担渚锤濠电娀娼ч悧蹇曞婵傚憡鍋i柛銉簻閻ㄥ搫顭胯濞叉﹢濡甸崟顖氬嵆妞ゅ繐妫涜摫缂傚倷鑳剁划顖滄崲閸岀儑缍栨繝闈涱儛閺佸洭鏌i幇顓烆棆闁烩晛娴风槐鎾诲磼濞嗘帒鍘¢梺绋款儐閹稿宕氭繝鍥ㄥ殟闁靛绲肩划鎾绘⒑瑜版帗锛熺紒鈧笟鈧幃鎸庛偅閸愨晝鍙嗗┑鐘绘涧濡厼危瑜版帗鐓曢悗锛卞啫鈷夌紓浣虹帛缁诲啰鎹㈠┑瀣<婵﹩鍘介宥夋⒑鏉炴壆顦﹂柣妤佹尭椤繘鎼圭憴鍕彴闂佺偨鍎村▍鏇㈡倶瀹ュ鈷戦柟绋垮绾炬悂鏌涢妸銈囩煓闁绘侗鍠楃换婵嬪炊閵娿儰姹楁繝鐢靛仩鐏忔瑧鍒掗鐐茬柧闁靛繈鍊栭埛鎴犵磼鐎n偄顕滄繝鈧幍顔剧<妞ゆ洖妫涢幃鍏间繆閸欏濮嶇€殿喖顭锋俊鐑芥晜鐟欏嫬顏归梻鍌欑閹诧紕鎹㈤崒婧惧亾濮橆剙妲婚崡閬嶆煙闂傚鍔嶉柣鎾跺枑娣囧﹪濡堕崒姘闂佽瀛╃喊宥咁熆濮椻偓閹儳鐣¢幍铏杸闂佹悶鍎崝宀勫礉閸涘瓨鈷戦柟绋挎捣缁犳挻绻涚拠褏鎮肩紒顕呭幗瀵板嫰骞囬娑欏缂傚倸鍊烽悞锕傛晪婵犳鍠栭ˇ鐢稿蓟濞戞瑦鍎熸繛鎴炃氶崑鎾斥攽鐎n亞鐣洪梺鐐藉劜閺嬬厧危閸儲鐓忛煫鍥堥崑鎾诲棘閵夈儰澹曢梺鍓插亝濞叉﹢鎮¢悢鍏肩厵闂侇叏绠戦悘锛勭棯椤撶偛鈷旈柟顕呭枛椤繈鎳滅喊妯诲闂備礁鎲$缓鍧楀磿鏉堛劎澧¢梻鍌欑劍鐎笛兠鸿箛娑樺瀭闁芥ê顦介崵鏇炩攽閻樺疇澹橀柣鎺撴そ閺屾盯骞囬妸锔界彅濡炪倕瀛╅幑鍥ь潖濞差亝鍤掗柕鍫濇噺閻庢儳鈹戦悩顔肩仾闁挎洏鍨介弫鎰版倷閸濆嫮顔婂┑掳鍊撶粈渚€鍩€椤掑倹鏆柟顔煎槻閳诲氦绠涢幙鍐х棯缂傚倷璁查崑鎾绘煕椤愮姴鍔滈柣鎾存礋閺岋絽螣閾忕櫢绱炴繝鈷€鍛毈闁哄本娲熷畷閬嶅即閻欌偓濡差喖顪冮妶搴′簼缂侇喗鎹囧畷娲焵椤掍降浜滈柟鐑樺灥椤忊晝绱掗悩宕囧⒌闁哄苯绉瑰畷顐﹀礋椤掆偓濞呫倝姊虹拠鈥崇仯闁稿鍋ゆ俊鐢稿礋椤栨氨鐤€闂佸疇妗ㄧ拋鏌ュ磻閹炬枼鏀介悗锝庝簽椤斿棙绻濋悽闈浶g痪鏉跨Ч閸╂盯骞掑Δ浣哄幈闁诲繒鍋炲畷妯荤珶濮椻偓閺屽秷顧侀柛鎾寸懇瀹曟煡寮婚妷锔剧暢闂傚倷鐒﹂幃鍫曞磿濠婂牆宸濇い鏃傜摂閸熷酣姊婚崒娆戭槮濠㈢懓锕幃锟犲醇閵夈儳锛涢梺鍛婄⊕濞兼瑩鎯屽Δ鍛彄闁搞儯鍔庨埊鏇㈡煟閹惧鎳囬柡宀€鍠栭、娑樷槈濞嗘垵鍤掗柣鐐寸瀹€绋款潖濞差亜绠柤鎭掑劜閺嗙姴鈹戦纭峰伐妞ゎ厾鍏樺畷娲焵椤掍降浜滈柟鍝勬娴滃墽绱撴担鍝勑㈢紒澶屾嚀閻g兘寮撮姀锛勫姸閻庤鎸堕崕鍗灻洪鈧偓浣糕槈閵忊€斥偓鐑芥煙缂佹ê绗ч柍褜鍓﹂崣鍐潖閾忓湱鐭欓悹鎭掑妿娴煎洭姊虹粙娆惧剳闁稿鍊濋獮鍐晸閻樺樊娼婇梺鐐藉劥鐏忔瑧绮诲顒夋富闁靛牆妫涙晶顒傜磼椤旇偐鐒搁柟顖氬暣楠炲鎮╅悽纰夌床闂佸搫顦悧鍕礉瀹€鍕紶婵炲樊浜濋悡娑㈡倶閻愰鍤欏┑鈥炽偢閺屽秶鎲撮崟顐や紝閻庤娲熸禍鍫曞春閿熺姴纾奸柛宀嬬畱椤╊剛绱掓潏銊﹀鞍闁瑰嘲鎳橀獮鎾诲箳瀹ュ拋妫滈梻鍌欐祰椤曆囧礄閻e瞼绀婇柛鈩冪☉绾捐霉閿濆懏璐℃い鈺佸级缁绘繃绻濋崒婊冾杸闂佺粯鎸荤粙鎾诲焵椤掆偓缁犲秹宕曢柆宥呯柈妞ゆ劧绲肩换鍡涙煕瑜庨〃鍡涙偂閸愵喗鐓㈡俊顖欒濡牊淇婇幓鎺撹础缂佽鲸甯炵槐鎺懳熼崗鐓庡灡闁诲氦顫夊ú鏍Χ閹间礁绠栭柕蹇嬪€栭幆鐐烘煕閿旇骞栭悽顖樺妼閳规垿鎮╅幇浣告櫛闂佸摜濮甸悧鐘诲极閸愵喖惟闁靛鍨洪悗娲⒑閹稿海绠撻柟鍐差槸鍗遍柛顐犲劜閻撶喖鏌曡箛濠冨殙闁荤喖鍋婇崯鍛節闂堟稒鍌ㄥù婊勭矒閺岋繝宕掑☉妯哄Б闁诲孩鑹鹃柊锝夊蓟瀹ュ牜妾ㄩ梺鍛婃尰瀹€绋跨暦濠靛鍗抽柍鍨涙杹閸嬫捇寮崼婵堫槰濡炪倖鏌ㄥΣ鍫n樄妤犵偞鐗滈崚鎺楀礂婢跺﹣澹曢梺鑲┾拡閸撴瑩宕甸鈧埞鎴︽偐閸偅姣勯梺绋款儑婵攱绂嶇粙搴撴瀻闁规儳纾悰銉╂⒑閸濆嫯鐧侀柛娑卞枟椤旀洘绻濋悽闈涗粶婵☆垰锕ョ粋宥呪堪閸喎鈧潡鏌涢…鎴濅簴濞存粍绮撻弻鐔煎传閸曨厜褎淇婇幆褍妲婚棁澶嬬節婵犲倸顏柣顓熷浮閺屸€崇暆閳ь剟宕伴弽褏鏆︽い鎰剁畱缁€瀣亜閹烘埈妲规い銉到閳规垿鎮欓懠顒佹喖缂備緡鍠楅幐鍓у垝婵犳艾鍐€鐟滄粌岣块弽銊х鐎瑰壊鍠曠花鑽ょ磼閻樺崬宓嗘鐐寸墪鑿愭い鎺嗗亾闁诲浚鍣i弻宥囨喆閸曨厸濮囩紓浣虹帛缁诲嫰宕版繝鍋界喎鐣℃0浣割棜闂備焦鍎冲ù姘跺磻閸涙潙绠栨繛鍡樻尰閻撴洘淇婇妶鍛櫢闁规煡绠栭弻鈥崇暆閳ь剟宕伴弽顓炵畺鐟滄柨鐣锋總鍛婂亜闁告繂瀚▓銉х磽閸屾艾鈧娆㈤敓鐘茬;闁告洦鍘鹃惌鎾舵喐閻楀牆绗掗柦鍐枑缁绘盯骞嬪▎蹇曞姶闂佽桨绀侀崯鎾蓟閵娿儮鏀介柛鈩兠粣娑㈡⒑娴兼瑧鎮奸柛妯犲洠鈧棃宕橀鍢壯囨煕閳╁厾顏堟瀹ュ應鏀介柨娑樺娴犫晜淇婇銏狀伃闁挎繄鍋犵粻娑樷槈濞嗘劕鍔掗梻渚€娼荤€靛矂宕㈡ィ鍐╂櫖婵犲﹤鍟犻弨浠嬫煃閽樺顥滈柣蹇曞█閺岀喓鍠婇崡鐐板枈闂佹寧绻勯崑娑㈡偩濠靛绀嬫い鎺嗗亾闁逞屽墮閻忔氨鎹㈠☉銏犻唶婵犻潧鐗呴搹搴♀攽閻愬弶鍣洪柨鏇樺灲瀵鈽夐姀鐘殿啋闁诲酣娼ч幉锟犲闯椤栫偞鈷戦悹鍥皺缁犱即鏌涢悢鍛婄稇妞ゎ偄绻愮叅妞ゅ繐瀚粣娑欑節閻㈤潧小闁煎啿澧庨幑銏$瑹閳ь剙顫忓ú顏勪紶闁靛鍎涢敐鍥e亾閸忓浜剧紓浣割儓濞夋洟寮抽敃鍌涚厪闊洤顑呴埀顒佹礈缁鎮烽幊濠傜秺閺佹劙宕ㄩ鐐剁窡闂備礁缍婇弨鍗烆渻閽樺娼栨繛宸簻瀹告繂鈹戦悩鎻掓殭闂傚绉归幃宄扳堪閸曨剛鍑¢梺鍝ュ櫏閸ㄥ磭鍒掔€n亶鍚嬮柛鈩冪懐濞村嫰鏌f惔顖滅У闁稿妫濆畷銏ゆ焼瀹ュ棛鍘介柟鍏兼儗閸ㄥ磭绮旈棃娴㈢懓饪伴崟顓犵厜濡炪們鍨哄Λ鍐€佸鈧慨鈧柨娑樺楠炲秵淇婇悙顏勨偓鏍ь潖瑜版帒鍑犲┑鐘崇閸も偓闂佺鍕垫畷闁绘挻绋戦湁闁挎繂姣ヨぐ鎺戞辈闁挎繂娲犻崑鎾舵喆閸曨剛顦ㄩ柣銏╁灡鐢繝宕洪妷锕€绶炲┑鐘插閸嶉潧顪冮妶鍡楀潑闁稿鎸剧槐鎺楁偐闂堟稐妲愬┑顔硷功缁垶骞忛崨顖滈┏閻庯綆浜濋鍕⒒娴e憡鍟為柛銊ョ秺瀵煡顢曢妶鍡╂綗闂佺粯鍔曢幖顐︾嵁閵忥紕绠鹃柟瀵稿亶缂傛岸鏌ㄥ☉娆戞创婵﹨娅i崠鏍即閻愭祴鎷ら梺钘夊暢妞村摜鎹㈠☉銏犲窛妞ゆ牗顕撮敐澶嬬厪闁搞儜鍐句純濡ょ姷鍋炵敮锟犵嵁鐎n亖鏀介柛鎰╁妺婢规洟姊洪悡搴綗闁稿﹥娲熻棢婵﹩鍏橀弨浠嬫煕鐏炲墽顣查柛鐔哄仱閺岋綁骞樼€涙ḿ顦伴梺璇″枟閿曘垽骞冨▎鎾崇闁瑰搫妫欑€垫牠姊绘担鍝ユ瀮婵☆偄瀚拌棟閺夊牃鏅滈~鏇㈡煙閻戞ê鐒炬繛鎾愁煼閺屻劑寮村Δ鈧禍鎯р攽閻愰鍤嬬紒鐘虫崌楠炲啴鍨鹃弬銉︾€婚梺瑙勫劤椤曨參宕㈡禒瀣拺缂備焦蓱閻撱儵鏌熺拠褏纾挎繛鍡愬灲瀹曪絾寰勯崼婊呯泿闂傚⿴鍋勫ù鍕緤閽樺鍤曟い鏇楀亾闁哄备鈧磭鏆嗛柍褜鍓熷畷浼村冀椤撶偟鐣洪梺鏂ユ櫅閸燁垶宕曢悢鍏肩厪闊洢鍎抽幃鍏笺亜閵忕姵鍤囨慨濠勭帛閹峰懘鎮滃Ο鐑樼暚闁诲孩顔栭崰鏍偉婵傚摜宓侀柟鐗堟緲缁€鍐煠绾板崬澧繛鍫ョ畺濮婅櫣绱掑Ο鑽ゅ弳闂佸憡鑹鹃澶庢"闂佸壊鍋嗛崰鎾剁不妤e啯鐓欓悗鐢登规禒褔鏌熼崘鎻掝伃闁哄矉绲介埞鎴﹀箻閸撲胶妲囨繝娈垮枛閿曘倝鈥﹀畡鎵殾闁圭儤鍩堝ḿ鈺傘亜閹达絾顥夊ù婊堢畺閺岀喖姊荤€靛壊妲紒鎯у⒔閹虫捇鈥旈崘顏佸亾閿濆簼绨奸柟鐧哥秮閺岋綁顢橀悙鎼闂侀潧妫欑敮鎺楋綖濠靛鏅查柛娑卞墮椤ユ艾鈹戞幊閸婃鎱ㄩ悜钘夌;闁绘劗鍎ら崑瀣煟濡崵婀介柍褜鍏涚欢姘嚕閹绢喖顫呴柣妯荤垹閸ャ劎鍘遍柣蹇曞仜婢т粙鎮¢姘肩唵閻熸瑥瀚粈鈧梺瀹狀潐閸ㄥ潡銆佸▎鎾村剹妞ゆ劦鍋傜花濠氭煟閿濆洤鍘存い銏☆殜瀹曠喖顢曢姀鐘辨喚闂備浇顕уù鐑藉极閸濄儲鍏滈柛顐f礀绾惧鏌熼幑鎰厫闁哥姴妫濋弻娑㈠即閵娿儱顫銈忚礋閸庡磭妲愰幘璇茬<婵ɑ鐦烽姀銈嗙叆闁哄洢鍔嬬花缁樸亜閺囶亞绋荤紒缁樼箓椤繈顢楅埀顒勬嚀閸喒鏀介幒鎶藉磹閺囥垺鏅濋柕鍫濐槸缁犳牠鏌熸潏楣冩闁抽攱鍨块弻娑樷槈濮楀牊顣肩紓浣哥埣娴滃爼寮诲☉銏犖╃憸搴♀枍閺囩喍绻嗛柛娆忣槸婵秹鏌$仦鑺ヮ棞妞ゆ挸銈稿畷鍗炩枎韫囨挾顔戦梻鍌欒兌椤㈠﹥绔熼崼銉ョ妞ゅ繐妫欓~鏇㈡煛閸ャ儱鐏柛瀣ф櫆閵囧嫰骞橀崡鐐典痪闂佺粯鎸诲ú鐔肩嵁閺嶎灔搴敆閳ь剚淇婂ú顏呯厵闁哄被鍎抽悾娲煙缁嬪尅宸ラ柍瑙勫灴瀹曚即濮€閻樼數楔閻庤娲橀〃濠傜暦濡ゅ懏鍤冮柍鍝勫暊閺嬪繒绱撻崒娆掑厡闁稿鎸搁悾宄拔熺悰鈩冪亙闂佸搫娲㈤崹褰掓倿閸偁浜滈柟鍝勬娴滃墽绱撴担鍝勑㈢紒澶屾嚀閻g兘寮撮姀锛勫姸閻庤鎸堕崕鍗灻洪敂閿亾娴e啫浜归柍褜鍓氱粙鎺楁晪婵炲瓨绮嶉〃濠傤潖濞差亜浼犻柛鏇ㄥ墮閸嬪秹姊洪幖鐐插婵$偘绮欓獮鍐灳閺傘儲顫嶉梺闈涢獜缁辨洟宕㈤柆宥嗏拺闂傚牊渚楀褏绱掗煫顓犵煓鐎规洘绻傞~婵嬵敄閼恒儲鏉搁梻浣瑰缁嬫垹鈧凹鍓涢弫顕€鎳滈悙閫涚盎濡炪倖鎸撮埀顒€鍟挎慨宄邦渻閵囧崬鍊荤粣鏃堟煛鐏炲墽娲村┑鈩冩倐婵″爼宕ㄩ鐘仏濠电姷鏁告慨顓㈠磻閹剧偨鈧帒顫濋敐鍛婵犳鍠栭敃銊モ枍閿濆洦顫曢柟鐑樺殾閻旂厧绠婚柧蹇e亯绾偓缂傚倷绶¢崰妤€螞閸愵喓鈧礁顫濈捄铏瑰姦濡炪倖甯掔€氥劑鍩€椤戣法绐旂€殿噮鍣e畷鐓庘攽鐎n亝鏆梻鍌欒兌缁垰螞娴g硶鏋嶉柨婵嗩槸濮规煡鏌曡箛瀣偓鏍煕閹烘鐓曢悘鐐村礃婢规﹢鏌嶈閸撴盯宕楀鈧獮鍐倷閻戞ɑ娅嗛梻浣诡儥閸ㄧ増绂嶉崜褏纾兼俊銈勮兌閳藉鏌熼崘鑼闁伙絿鍏樺濠氬Ψ閿旀儳骞堥梺璇茬箳閸嬬喖鎼规惔銊ュ惞闁靛牆妫涚粻楣冩煙鐎电ǹ鍓遍柣鎺撴倐閺岋繝宕橀妸褍顣洪悗鐟版啞缁诲啴濡甸崟顖氱閻犺櫣娲呴姀鈽嗘闁绘劖娼欏ù顔芥叏婵犲嫮甯涢柟宄版嚇瀹曘劍绻濋崘銊ュ濠电姷鏁搁崑娑㈡儑娴兼潙鍨傞柦妯侯槺閺嗭箓鏌i悢绋挎珵婵炲樊浜堕弫鍌炴煕濞戝崬骞掔紒銊ф暬濮婄粯鎷呴崨濠傛殘闂佸憡妫戦梽鍕矉瀹ュ應鏀介悗锝庝簽閻涖儵姊鸿ぐ鎺戜喊闁告ê澧藉褔鍩€椤掍胶绡€闁汇垽娼у瓭闂佺ǹ锕︾划顖炲疾閸洖鍗抽柣妯兼暩閿涙粓姊洪柅鐐茶嫰婢у鈧娲栭妶鎼佸箖閵忋垻鐭欓柛顭戝枙缁辩喎鈹戦悩娈挎毌婵℃彃鎳樺畷瑙勬綇閳规儳浜剧紒妤佺☉閹冲繘宕楀⿰鍏炬棃鏁愰崨顓熸闂佺粯鎸堕崹浠嬪蓟濞戙垹绠涢柛蹇撴憸閻╁酣姊洪崫鍕靛剱闁烩晩鍨跺濠氭晬閸曨亝鍕冮梺缁樺姦閸撴盯藝閵娧呯=濞达綀娅g敮娑氱磼鐎n偆澧甸挊婵嬫煛鐏炶鍔滈柛濠傜仛閹便劌螣閸濆嫯鍩為梺鍛娒顓㈠焵椤掑喚娼愭繛鍙夛耿瀹曞綊骞愭惔婵堢畾闂佸綊妫跨粈渚€鎮″☉銏$厱閻忕偟铏庡▓鏇㈡倵濮樺啿浜圭紒杈ㄦ崌瀹曟帒顫濋钘変壕闁绘垼濮ら崐鍧楁煥閺囩偛鈧綊寮查鍕ㄦ斀闁绘ɑ鍓氶崯蹇涙煕閻樺磭澧悡銈夋煥閺囩偛鈧憡顢婇梻浣告啞濞诧箓宕规导鏉戠闁规儼濮ら悡蹇撯攽閻愯尙浠㈤柛鏃€姘ㄧ槐鎺楊敃閵忊懣褎鎱ㄦ繝鍛仩闁告牗鐗犲鎾偄閸涘﹦缈婚梻鍌欑劍閹爼宕濊箛鎾愭盯宕熼锝嗘櫔闂佹寧绻傞ˇ顖滅不缂佹ǜ浜滈柡鍐ㄥ€甸幏鈩冪箾閻撳函韬慨濠冩そ閹瑩鎸婃径濠傤潥闂備礁鎼鍛村Χ缁嬭法鏆﹂柟杈剧畱缁犺崵绱撴担濮戭亝绂掑ú顏呪拺闁告稑锕﹂埥澶愭煥閺囶亞鐣电€规洩缍佸畷鍗烆渻缂佹ɑ鏉搁梻浣虹帛宀h法鍒掗姘f鐟滃孩绌辨繝鍥舵晝闁挎繂瀛╅悿渚€姊虹化鏇熸澒闁稿鎸搁—鍐Χ閸℃鐟ㄩ梺绋匡工缂嶅﹤鐣烽悽绋跨劦妞ゆ帒瀚埛鎴︽倵閸︻厼顎岄柛銈嗙懅缁辨帗寰勭仦鎯ф畬闂佷紮绲块崗妯虹暦婵傜ǹ鍗抽柣鎰М閺呯娀寮婚妸銉㈡斀闁糕剝顨忔导鈧梻浣哄劦閺呮盯鏌婇敐鍜佹綎缂備焦岣跨弧鈧柟鑲╄ˉ閳ь剝灏欓惄搴㈢節閻㈤潧浠╂い鏇熺矋娣囧﹪宕堕埡浣哥亰濠电偛妫欓幐鍝ョ不濞戙垺鐓涘璺哄绾爼鏌i妶鍛櫤濞e洤锕俊鎯扮疀閺囩偛鐓傞梻浣告憸閸c儵宕归崼鏇炵畺闁炽儲鏋煎Σ鍫ユ煏韫囧ň鍋撻弬銉ヤ壕闁割偅娲橀悡鐔兼煙閹殿喖顣兼繛鎳峰厾鐟扳堪閸愩劉鎸冪紓浣介哺鐢繝宕洪埀顒併亜閹烘垵鈧敻宕戦幘缁樻櫜閹肩补鈧啿绠i梻浣呵归鍡涘箰妤e啫绠熼柟缁㈠枛缁€瀣亜閹烘垵浜炴俊鑼嚀閳规垿鎮欓懠顒佹喖缂備緡鍠栭惌鍌炲箖閵夛妇闄勭紒瀣嚦閵夈儍褰掓晲閸涱収妫屽┑鐐殿儠閸旀垿寮诲鍫闂佸憡鎸鹃崰鏍偘椤曗偓瀹曟﹢顢欑喊杈ㄧ秱闂備焦瀵х粙鎴犫偓姘緲椤﹪顢欓悾宀€鐦堥梺闈涢獜缁插墽娑甸悙顑句簻闁挎洑绶氶崫铏光偓鍨緲鐎氫即寮幘缁樻櫢闁跨噦鎷�
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者