C#复合控件构建
这个ListMover控件包含两个EnhancedListBox控件,还有一些按钮用于在两个列表之间来回移动项。借助于这些C#复合控件构建技术,你可以学习如何创建子控。对于这个控件,你要注意的是某些事情必须发生的位置。
首先,借助于与在以前的控件中相同的技术,你必须把在这个控件中需要的JavaScript代码添加到OnInit事件的重载版本中。如你在上一个控件中所做的一样,你也是使用JavaScript存取一个ListBox中的元素。而且,我已经编制了函数分别实现把项添加到一个列表,从一个列表中删除项,以及从一个列表中添加或删除所有项。
我已经进行了功能的分离,而不是创建单个“move”方法;这样以来,我可以实现基于属性设置而使得从一个列表中删除项成为可选的。毫无疑问,这可以使最终的控件更为强壮些,但是我在本文中不再分析这些代码。还应该注意,就象在前面控件中一样,我也添加了一个BuildItemList方法。
现在,你需要把这一客户端代码依附到复合控件的按钮中。你可以在CreateChildControls方法的最后完成这一点;并且,在此时,完成子控件的初始化和构建控件集合。在此,我仅向你展示相应于一个按钮的代码(另外的按钮代码与此类似,省略)。
- string s_AddToLeft = "AddSelectedItemToList(document.all." +
- this.lstItemsOnRight.ClientID + ", document.all."
- + this.lstItemsOnLeft.ClientID + ", " +
- (this.AllowDuplicatesOnLeft ? "true" : "false") + "); ";
- string s_RemoveFromRight = "RemoveSelectedItemFromList(document.all." +
- this.lstItemsOnRight.ClientID + "); ";
- string s_BuildItemList = "BuildItemList(document.all." +
- this.lstItemsOnRight.ClientID + ", document.all.__" + lstItemsOnRight.ClientID + ");
- " + "BuildItemList(document.all." + this.lstItemsOnLeft.ClientID + ", document.all.__"
- + lstItemsOnLeft.ClientID + "); ";
- this.btnAdd.Attributes.Add("onclick", s_AddToLeft
- + " " + s_RemoveFromRight + " " + s_BuildItemList
- + " return false");
注意,我实现了在以前的控件中同样的工作。我把JavaScript函数调用构建成一字符串并且把它们依附到一个按钮上。主要区别在于,既然这是一个包含其它控件的复合控件,那么你可能使用把代码添加到onclick事件的Attributes.Add方法,这与在一个生成控件中把它放到一个栈上的方法形成对照。还要注意,我把多个功能放到onclick属性中;而且,函数调用的最后返回false以便取消按钮将执行的任何回寄。
最后,代码将在一个对Render重载的方法中初始化对客户端函数BuildItemList的调用。这看起来很象我在 EnhancedListBox控件中向你介绍的那个,在此不再重复。注意,在这个控件中,我注册了两个隐藏的文本域,每一个相应于一个ListBox。
- protected override void OnPreRender(EventArgs e)
- {
- base.OnPreRender(e);
- if(Page != null)
- {
- Page.ClientScript.ReGISterHiddenField("__" + this.lstItemsOnRight.ClientID,
- "");
- Page.ClientScript.RegisterHiddenField("__" + this.lstItemsOnLeft.ClientID,
- "");
- Page.RegisterRequiresPostBack(this);
- }
- }
现在,C#复合控件构建成功,能够提供一些客户端JavaScript,并且把它绑定到按钮上。与以前一样,你可以把它放到一个表单上并且使用它;但是,在你添加同步代码之前,它仍将会遇到你在第一个控件中所遇到的问题—你可以前后移动项,但是一旦你初始化一个回寄(通过表单上的任何其它控件),该控件就会恢复到它回寄之前的状态。
为了修改这个问题,你要实现你在第一个控件中所做的同样的工作。然而,既然你在开发一个复合控件,而不是扩展一个已经现有的控件,那么你需要实现IPostBackDataHandler接口并且提供LoadPostData和 RaisePostDataChangedEvent方法的实现代码。这些实现与前面的控件基本一致,除了你要实现两个 EnhancedListBox控件中的项集合的同步而不是只考虑一个控件外。并且与以前一样,你需要确保你保存你的SelectedIndex位置;这样以来,在你完成项集合的同步后你就可以把它们设置回去。还要注意,在第一个控件中,你重载了基控件的LoadPostData方法,因此在某处调用了它的基类。现在,既然你要从头编写一个复合控件,那么就没有基类可调用,而仅需提供你自己的方法实现。
这个控件的最后版本包含若干新的属性:包括用来决定是否添加到一个列表中的项能够被从另一个列表中删除的属性(如果一个列表将允许出现重复项的话);它还包含可扩展的风格化以实现最大化重用的目的,等等。
就这些。你已经使用了可用于客户端脚本中的隐藏的文本域来存储列表框的状态。在回寄期间,你使用隐藏文本域的内容来与服务器端项集合重新同步。最终结果是一个漂亮的复合控件—允许你在没有服务器回寄的情况下实现各列表项间的来回移动,而当一个回寄真正发生时仍能够保持这种变化。以上介绍C#复合控件构建
【编辑推荐】