65.9K
CodeProject 正在变化。 阅读更多。
Home

Extender Provider 简化文件/文件夹选择

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.71/5 (17投票s)

2005年1月5日

CPOL

4分钟阅读

viewsIcon

60367

downloadIcon

428

让用户选择文件或文件夹的常见任务,封装在 IExtenderProvider 实现中。

Sample Image - FileBrowserExtender.jpg

引言

你是否曾经编写过一个配置对话框,要求用户为你的应用程序输入一个文件名或路径来执行某些操作?

如果你写过,那么你可能已经添加了一个按钮来浏览文件或文件夹,并编写了一些相当琐碎的 Click 事件处理程序:实例化相应的 FileDialogFolderBrowserDialog,设置其属性,调用 ShowDialog(),如果 DialogResultDialogResult.OK,则用对话框中的文件名或文件夹填充关联的 TextBox

没什么大不了的,你可能会说。

你说得对。

这是一个标准的过程,一点也不难,但为了让配置对话框更用户友好,你必须这样做。当你有很多配置对话框或需要配置多个文件路径/文件夹时,你会发现自己一遍又一遍地编写相同的琐碎代码。

所以我想到可以稍微简化这个重复性的任务,并重新温习一下我对 extender provider 的知识...

File/FolderBrowserExtenderProvider 组件

基于 IExtenderProvider 的方法看起来很合适:将两个控件绑定在一起,一个充当“浏览”按钮,另一个接收选择的文件或文件夹。

我选择的方法是让 extender provider 扩展接收所选文件/文件夹的控件,并提供用于启动浏览的按钮。

编写 extender provider

要开发这样的组件,你需要继承 IExtenderProvider,并在 ProvidePropertyAttribute 中指定要提供的属性的名称,如下所示:

[ProvideProperty("BrowseButton", typeof(Control))]
public class FolderBrowserExtenderProvider : Component, IExtenderProvider

这样,我就指定了我的 extender provider 将为某些组件添加一个名为“BrowseButton”的附加属性,并且该属性是一个 Control

下一步是说明哪些组件可以被新的 extender provider 扩展。

这通过实现 CanExtend() 来完成。给定一个可扩展对象(即将被扩展的对象),你的 extender provider 必须告知它是否能为该对象提供给定的属性。

起初,如果可扩展对象派生自 TextBoxBase,我就会返回 true(通常你需要:在 TextBox 中输入文件名/文件夹),但过了一段时间,我想到不必将开发者限制于这种类型。任何控件都有一个 Text 属性,可以接收所选的文件/文件夹名称,所以现在这个函数对 Controls 返回 true

接下来,你需要处理新属性的设置和检索。

extender provider 实际上并没有以一种你可以实际写的方式向可扩展对象添加新属性:

myTextBox.BrowseButton = myButton;

相反,它的职责是维护一个可扩展对象及其分配属性的列表。这样的列表条目是通过调用来创建的:

Set<PropertyName>(extendee, property value)

并通过调用来查询:

Get<PropertyName>()

在我的例子中,这些方法的签名如下:

public Control GetBrowseButton(Control extendee);

public void SetBrowseButton(Control extendee, Control browseButton);

我认为大多数 extender provider 会使用 HashTable 来维护分配,这样很容易跟踪。我的组件就是这样做的。

为 extender provider 添加功能

到目前为止,我们的 extender provider 除了记住哪个控件被分配为 BrowseButton 给哪个其他控件之外,并没有做任何事情。为了在点击分配的 BrowseButton 时实际开始浏览,一旦分配了 BrowseButton,我们就必须为其添加一个 Click 事件处理程序。

虽然你很少会删除或重新分配可扩展对象,但在 BrowseButton 被重新分配之前移除事件处理程序是个好主意,否则你会发现多个对话框弹出。

Click 事件处理程序最终负责显示相应的 FileFolderBrowserDialog。为了能够可视化设计这个对话框,每个 extender provider 都有一个公共只读属性 FileDialogFolderBrowserDialog

这里有一个小细节:为了让设计器正确地序列化对话框的属性,我必须将 DesignerSerializationVisibilityAttribute 设置为 DesignerSerializationVisibility.Content,否则会序列化对话框本身的引用而不是对话框的属性。

使用 extender providers

要在你的窗体中使用 extender providers,你应该将它们添加到你的工具箱中。然后将它们拖到你的窗体上,你的每个控件都会显示一个额外的属性 BrowseButton,默认值为 None

只需选择你希望点击的控件以显示相应的浏览对话框,并将选择的文件夹/文件传输到第一个控件的文本中。

一个基本场景是在你的 Form 上有一个 TextBoxtextBox1)和一个 Buttonbutton1)。

你将一个 FolderBrowserExtenderProvider 添加到 Form,并将 textBox1BrowseButton 属性设置为 button1,这样就完成了。

顺便说一句,你可以将一个控件分配为自己的 BrowseButton。不幸的是,由于 VS 代码生成中的一个 bug,你无法在视觉上做到这一点,否则你会得到错误的 C# 代码。由于至今没有解决方法或修复,我在设计器中尝试进行此类分配时会抛出异常。

但是,你可以在代码中毫无问题地分配 BrowseButton

如果你不确定,只需查看源代码中包含的示例应用程序。

修改历史

  • 2004.01.05 - 首次发布。
© . All rights reserved.