在 Web 部件系列文章的上一篇中,创建了一个带有个性化的 Customer 属性的自定义 Web 部件。我们的本意是让这个属性决定 Web 部件里的 GridView 的内容是为一个客户显示信息还是为所有客户显示信息。但你不能通过 Web 部件页面的用户界面来改变这个属性,那么,现在就开始讲述如何实现这点。
ASP.NET Web 部件框架提供了编辑 Web 部件属性的功能。如你在创建切换页面 DisplayMode 的 Menu 控件时所见,它包括一个 Edit 模式。然而,如果尝试激活它,将得到一个在页面上缺少控件的异常。
Edit 模式缺少的部分是 EditorWebZone 和一些合适的编辑器部件,这二者都是预置的。 WebPartZone 是编辑器部件的宿主。看下面代码:
<asp:EditorZone runat="server" ID="SimpleEditor" >
<ZoneTemplate>
<asp:PropertyGridEditorPart runat="server" ID="MyGridEditor" />
<asp:AppearanceEditorPart ID="MyMainEditor" runat="server" />
</ZoneTemplate>
</asp:EditorZone>
AppearanceEditorPart 允许你配置 Web 部件的外观,包括标题和色彩设置。现在切换页面打开编辑器的效果如下:
ASP.NET 提供的编辑器 Web 部件
AppearanceEditorPart | 允许配置 Web 部件的基本属性,包括标题和 ChromeStyle |
BehaviorEditorPart | 修改影响 Web 部件行为的属性的编辑器。例如 AllowClose、AllowMinimize,以及 TitleUrl、HelpUrl、HelpMode等 |
LayoutEditorPart | 允许用户修改 Web 部件的区域和 ChromeState 。这个编辑器用于那些不能通过拖曳来改变 Web 部件的区域的浏览器 |
PropertyGridEditorPart | 为自定义 Web 部件的每一个包含 [WebBrowsable(true)] 特性的公共属性显示一个文本框 |
PropertyGridEditorPart 编辑器部件是一种让用户能修改 Web 部件上之前实现的 Customer 属性的正确做法。效果见上图可编辑的 Customer 属性。
由于在上篇文章的示例中,已经在属性设置方法里调用了 BindGrid()方法,一单击 EditorZone 的 应用按钮,Web 部件的外观立即就会改变。此外,除了添加 [WebBrowsable] 特性之外,如果你还给自定义属性添加 [WebDisplayName] 特性,就可以控制编辑器显示的属性名。
创建自定义编辑器
显示用户必须在其中手工输入客户 ID 的来选择客户的一个文本框并不是好的解决方案。创建一个自定义编辑器让用户从列表里选择客户会更方便。
为 Web 部件页面创建自定义编辑器很容易,只需要从 EditorPart 继承即可:
public class CustomerEditor:EditorPart
{
public CustomerEditor()
{
//
//TODO: 在此处添加构造函数逻辑
//
}
public override bool ApplyChanges()
{
// Initialize EditorPart with values from WebPart
}
public override void SyncChanges()
{
// Apply changes to the WebPart's properties
}
}
因为自定义编辑器只是一个组合控件,可以通过覆盖 CreateChildControls()方法来添加子控件,这样,你就需要创建一个列表来显示数据库中可用的用户:
private ListBox CustomerList;
protected override void CreateChildControls()
{
CustomerList = new ListBox();
CustomerList.Rows = 4;
this.Controls.Add(CustomerList);
}
创建完列表后,可以在 EditorPart 控件的初始化阶段加载数据了。假设已经有一个强类型的 DataSet 来访问数据库了,可以捕获 Init 事件并加载客户数据:
public CustomerEditor()
{
this.Init += new EventHandler(CustomerEditor_Init);
}
void CustomerEditor_Init(object sender, EventArgs e)
{
EnsureChildControls();
// Don't forget to use the DataSet's namespace
CustomerTableAdapter adapter = new CustomerTableAdapter();
CustomerList.DataSource = adapter.GetData();
CustomerList.DataTextField = "CompanyName";
CustomerList.DataValueField = "CustomerIDs";
CustomerList.DataBind();
// Add an 'empty' item to the list at the first position
// That means when the user selects this empty entry,
// all customers should be displayed.
CustomerList.Items.Insert(0, "");
}
最后,必须同步 EditorPart 和实际 Web 部件之间的修改。首先,如何从 Web 部件获得信息呢?要达到此目的,必须添加代码到 SyncChanges()方法,这也是继承 EditoePart 类必须覆盖的方法。
在这个方法里,通过基类的属性 WebPartToEdit 访问要被编辑的 Web 部件:
public override void SyncChanges()
{
// Make sure that all controls are available
EnsureChildControls();
// Get the property from the WebPart
CustomerNotesPart part = base.WebPartToEdit as CustomerNotesPart;
if (part!=null)
{
CustomerList.SelectedValue = part.Customer;
}
}
当用户在编辑器里单击 Apply 按钮来更新值时,你必须同时更新 Web 部件的属性。可以在 ApplyChanges()里实现:
public override bool ApplyChanges()
{
EnsureChildControls();
CustomerNotesPart part = (CustomerNotesPart)base.WebPartToEdit;
if (part!=null)
{
if (CustomerList.SelectedIndex>=0)
{
part.Customer = CustomerList.SelectedValue;
}
else
{
part.Customer = string.Empty;
}
}
else
{
return false;
}
return true;
}
如果属性值被成功更新,该方法返回 true,否则返回 false。基本上,这样就已经创建了一个自定义编辑器。
但是,该如何使用它呢?无论如何,基础设施必须知道这个编辑器只能用于指定的 Web 部件,在本例中就是 CustomerNotesPart 。要达到此目的,修改最初创建的 Web 部件,这个 Web 部件必须实现 IWebEditable 接口:
EditorPartCollection IWebEditable.CreateEditorParts()
{
// Create editor parts
List<EditorPart> Editors = new List<EditorPart>();
CustomerEditor Editor = new CustomerEditor();
Editor.ID = this.ID + "_CustomerEditor_1";
Editors.Add(Editor);
return new EditorPartCollection(Editors);
}
object IWebEditable.WebBrowsableObject
{
get { return this; }
}
这个方法对于用户控件和服务器控件都有效。包装了用户控件和服务器控件的 GenericWebPart 确认包装的控件是否实现了 IWebEditable 接口。如果该控件实现了这个接口, GenericWebPart 就调用这个接口的实现来提供自定义编辑器。
CreateEditorParts()只为这个 WebPart 控件返回一个 EditorParts 集合以供显示,而且 WebBrowsableObject 返回包含个性化属性的类。如这个典型的,可编辑的 WebPart 控件。