如何使自定义控件的 属性 打开文件对话框?

How do I make a property of a custom control open a file dialog?

我有一个带有 属性 的自定义控件,它保存目标计算机上存在的文件位置的名称(完整路径)。

确切的路径会根据目标电脑的类型而有所不同,通常是在我将自定义控件添加到我的表单之后立即设置的,而我仍处于项目的设计模式,因此当我的应用程序运行时,它从 属性 中获取文件名。

如果 属性 打开一个文件对话框让我浏览到该位置会很方便(类似于浏览图像和颜色属性时打开对话框的方式),但这似乎并不在visual basic中是可能的。

谷歌搜索几天后,我找到了几篇涉及其他编程语言主题的文章(请参见下面的示例片段),但我一直无法弄清楚如何使其适用于 Visual Basic。

这是我发现的一个片段,其中提到了编辑器的使用,这可能是入门的线索。

[Editor(typeof(FileSelectorTypeEditor), typeof(UITypeEditor))]
public string Filename
{
   get { return _filename; }
   set { _filename = value; }
}

希望有人能引导我走正确的路。

FileSelectorTypeEditor 可能是源自 FileNameEditor or FolderNameEditor 的自定义 class。

您可以使用标准 class 实现两者,或者使用您自己的扩展默认设置,正如您在您找到的那些 C# 源代码中看到的那样。

这里我用的是专门的FileNameEditorclass,命名(有点缺乏想象力)SpecializedFileNameEditor和标准的FolderNameEditorUITypeEditor 分配给 class 的两个属性。

ImagePath 属性 编辑器是 SpecializedFileNameEditor 对象,它使用 OpenFileDialog,其中预先选择了一个过滤器。它还覆盖 EditValue 方法,以将关联的 属性(此处为 ImagePath)的当前值(如果有)设置为 InitialDirectory OpenFileDialog 的。
ImageFolder 属性 编辑器是标准的 FolderNameEditor,它会打开一个 FolderBrowserDialog。

我还附加了一个 ExpandableObjectConverter 类型转换器,因此您可以在 PropertyGrid 中将这两个属性显示为可扩展的 属性 选择器。

你可以在这里看到一个例子:

Imports System.ComponentModel
Imports System.Drawing.Design
Imports System.IO
Imports System.Windows.Forms
Imports System.Windows.Forms.Design

<TypeConverter(GetType(ExpandableObjectConverter))>
Public Class ImagePickerClass

    Public Sub New()  
        ' Initialize [...]
    End Sub

    <Editor(GetType(SpecializedFileNameEditor), GetType(UITypeEditor))>
    Public Property ImagePath As String

    <Editor(GetType(FolderNameEditor), GetType(UITypeEditor))>
    Public Property ImageFolder As String

    Public Class SpecializedFileNameEditor
        Inherits FileNameEditor

        Private currentValue As String = String.Empty

        Public Overrides Function EditValue(context As ITypeDescriptorContext, provider As IServiceProvider, value As Object) As Object
            If TypeOf value Is String Then
                currentValue = DirectCast(value, String)
            End If
            Return MyBase.EditValue(context, provider, value)
        End Function

        Protected Overrides Sub InitializeDialog(ofd As OpenFileDialog)
            MyBase.InitializeDialog(ofd)
            If Not currentValue.Equals(String.Empty) Then
                ofd.InitialDirectory = Path.GetDirectoryName(currentValue)
            End If
            ofd.Filter = "PNG Images (*.png)|*.png"
        End Sub
    End Class
End Class