第一天:用UpdatePanel建造Widget的容器
这里有两个概念,一个是Widget容器一个是Widget. Widget容器只是提供一个头和内容的区域.Widget加载在Widget容器的内容区域.在这个页面里每个Widget初始化是通过WidgetContainer 服务器端控件动态创建的.实际上Widget也是服务器控件在Widget容器内部动态创建.
在整个页面刷新或者单个Widget更新的时候每个Widget都是通过里面包含的更新控制板来获取更新的.例如.Widget实际是在容器内的UpdatePanel里加载.因此,不论怎么样Widget都不会回调数据.
正确的组合UpdatePanel和UpdatePanel里的Html Elements是比较困难的.比如,第一次我在Widget里面放了一个UpdatePanel.当每个widget里面只有一个UpdatePanel时,它工作的很好.但是UpdatePanel里面的HTml附加的扩展是个问题.当UpdatePanel刷新的时候,他会创建一个新的,Html扩展就不存在了.由于所有的扩展附属与先前的Html上,要想不丢失必须这些扩展也在UpdatePanel里面.把扩展放到UpdatePanel的意思是,不论UpdatePanel什么时候刷新,新的扩展实例都要创建和初始化.创建这个UI是非常慢的.你可以看到当widget回调的时候很迟缓.
因此.最终的方案是把标题区域和内容区域分开到多个UpdatePanel里面.一个UpdatePaenl负责标题区域一个负责widget.当Widget做一些事情的时候需要widget刷新就不需要标题刷新了,并且扩展可以附加到标题那么就不会丢失啦.CustomFloatingBehavior 就是附加到标题的扩展程序.同样的这个扩展程序需要放到UpdatePanel里面.但是把扩展程序放到UpdatePanel里面就需要每次UpdatePanel刷新就要创建和初始化一次.这样的性能不是很好.
800)this.style.width=800;” src=”http://www.codeproject.com/Ajax/MakingGoogleIG/WidgetContainer1.png” alt=”Widget Container first idea” onclick=”window.open(this.src)” style=”cursor: pointer” />
因此,到目前为止,最好的方案是两个UpdatePanel在每个WidgetContainer里面,一个只是包含标题内容,但不是真个标题部分.当这个标题UpdatePanel刷新的时候.DIV包含的标题部分在UpanelPanel外面而不需要刷新.这样我们也可以放一个CustomFloatingBehavior 扩展程序在UpdatePanel外面.这样这个扩展就可以附加到标题容器的DIV上了.
800)this.style.width=800;” src=”http://www.codeproject.com/Ajax/MakingGoogleIG/WidgetContainer2.png” alt=”Widget Container final idea” onclick=”window.open(this.src)” style=”cursor: pointer” />
这个WidgetContainer 十分简单.他有一个包含标题名称和展开/折叠/关闭按钮的标题部分和一个包含Widgegt的内容区域.在这个方案里”WidgetContainer.ascx” 文件是WidgetContainer.
<asp:Panel ID=”Widget” CssClass=”widget” runat=”server”>
<asp:Panel id=”WidgetHeader” CssClass=”widget_header” runat=”server”>
<asp:UpdatePanel ID=”WidgetHeaderUpdatePanel” runat=”server”
UpdateMode=”Conditional”>
<ContentTemplate>
<table class=”widget_header_table” cellspacing=”0″
cellpadding=”0″>
<tbody>
<tr>
<td class=”widget_title”><asp:LinkButton ID=”WidgetTitle”
runat=”Server” Text=”Widget Title” /></td>
<td class=”widget_edit”><asp:LinkButton ID=”EditWidget”
runat=”Server” Text=”edit” OnClick=”EditWidget_Click” /></td>
<td class=”widget_button”><asp:LinkButton ID=”CollapseWidget”
runat=”Server” Text=”" OnClick=”CollapseWidget_Click”
CssClass=”widget_min widget_box” />
<asp:LinkButton ID=”ExpandWidget” runat=”Server” Text=”"
CssClass=”widget_max widget_box” OnClick=”ExpandWidget_Click”/>
</td>
<td class=”widget_button”><asp:LinkButton ID=”CloseWidget”
runat=”Server” Text=”" CssClass=”widget_close widget_box”
OnClick=”CloseWidget_Click” /></td>
</tr>
</tbody>
</table>
</ContentTemplate>
</asp:UpdatePanel>
</asp:Panel>
<asp:UpdatePanel ID=”WidgetBodyUpdatePanel” runat=”server”
UpdateMode=”Conditional” >
<ContentTemplate><asp:Panel ID=”WidgetBodyPanel” runat=”Server”>
</asp:Panel>
</ContentTemplate>
</asp:UpdatePanel>
</asp:Panel>
<cdd:CustomFloatingBehaviorExtender ID=”WidgetFloatingBehavior”
DragHandleID=”WidgetHeader” TargetControlID=”Widget” runat=”server” />
当页面加载每个widget初始化,第一个widget容器创建接着widget在容器内部创建.WidgetContainer是核心框架和Widget之间通道,通过他提供的API来存储状态或者改变状态,像展开/折叠等等.
当Widget折叠或者关闭等等信息也是通过WidgetContainer传递的.
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
var widget = LoadControl(this.WidgetInstance.Widget.Url);
widget.ID = “Widget” + this.WidgetInstance.Id.ToString();
WidgetBodyPanel.Controls.Add(widget);
this._WidgetRef = widget as IWidget;
this._WidgetRef.Init(this);
}
Widget容器首先通过Widget定义的Url地址加载widget.然后把widget放到内容panel里.It also passes its own reference as IWidgetHost to the actual widget
WidgetContainer实现了IWidgetHost接口使目前的widget与框架和容器来通信.
public interface IWidgetHost
{
void SaveState(string state);
string GetState();
void Maximize();
void Minimize();
void Close();
bool IsFirstLoad { get; }
}
执行起来非常的简单.比如.可以用IWidgetHost.Minimize 来折叠Widget内容区域.
首先我们更新WidgetInstance 然后刷新UI.这个Widget也通过IWidget接口获得一个回调.
除了Close以外IWidgetHost都能容易的实现所有的功能.当发起Close信号的时候,我们需要在这个页面移除这个Widget.就是说,WidgetContainer还在这个页面而这个WidgetInstance要从数据库移除.WidgetContainer 自己是不能做到的.需要通过包含WidgetContainer的所在列来实现.Default.aspx包含所有的WidgetContainer.因为,当Close事件触发的时候,WidgetContainer给Default.aspx产生一个事件,并且default.aspx移除这个Widget和刷新这列.
void IWidgetHost.Minimize()
{
DatabaseHelper.Update<WidgetInstance>(this.WidgetInstance,
delegate(WidgetInstance i)
{
i.Expanded = false;
});
this.SetExpandCollapseButtons();
this._WidgetRef.Minimized();
WidgetBodyUpdatePanel.Update();
}



备注
using (TransactionScope ts= new TransactionScope())

{
//自定义操作
}
}