В Windows Forms я представляю пользовательский класс в элементе управления PropertyGid, который имеет различные строковые свойства, как вы можете заметить на следующем изображении:

enter image description here

Проблема в том, что меня не устраивает текущее поведение при изменении значения свойств строки. Для тех свойств, которые ожидают путь к файлу или каталогу, например свойства "Target" или "Working Directory", я хотел бы знать, возможно ли и целесообразно ли реализовать дескриптор TypeConverter / Type, который бы открывал OpenFileDialog при нажатии на стрелку вниз справа от поля в сетке свойств. То есть, чтобы выбрать файл или папку через OpenFileDialog, вместо прямой записи пути в сетке свойств, но, тем не менее, предоставьте возможность прямой записи пути, если я хочу это сделать.

Может быть, библиотека классов .NET Framework уже предоставляет TypeConverter / TypeDescriptor, который я запрашиваю? Если нет, то возможно ли это сделать? И как начать это делать?

Или любая другая идея, чтобы иметь возможность открыть OpenFileDialog для изменения значения определенного свойства в элементе управления PropertyGrid ?.

1
ElektroStudios 28 Май 2019 в 15:42

2 ответа

Лучший ответ

Есть встроенные { {X0}} и FolderNameEditor Редакторы типа пользовательского интерфейса, которые позволяют выбрать имя файла и имя папки, например:

using System.ComponentModel;
using System.Drawing.Design;
using System.Windows.Forms;
using System.Windows.Forms.Design;
public class MyClass
{
    [Editor(typeof(FileNameEditor), typeof(UITypeEditor))]
    public string FilePath { get; set; }

    [Editor(typeof(FolderNameEditor), typeof(UITypeEditor))]
    public string FolderPath { get; set; }
}

Если вы хотите настроить FileNameEditor для отображения только текстовых файлов, вы можете переопределить его InitializeDialog метод:

public class MyFileNameEditor : FileNameEditor
{
    protected override void InitializeDialog(OpenFileDialog openFileDialog)
    {
        base.InitializeDialog(openFileDialog);
        openFileDialog.Filter = "text files (*.txt)|*.txt";
    }
}
1
Reza Aghaei 28 Май 2019 в 19:49

В моем приложении у меня есть свойство, которое принимает путь к файлу значка, другое свойство, которое может принимать файл или папку, и другое свойство, которое принимает путь к папке.

Итак, я должен был написать варианты для каждого из этих свойств ...

Самый простой способ, и в случае, если вы удовлетворены внешним видом и ограничениями FolderBrowserDialog, это непосредственно указать класс System.Windows.Forms.Design.FolderNameEditor в классе EditorAttribute. В противном случае Ooki.Dialogs является хорошей библиотекой с открытым исходным кодом в качестве альтернативы, чтобы получить диалог в современном стиле.

Второй самый простой - это редактор для выбора пути к файлу иконки:

''' <summary>
''' Provides a user interface for selecting a icon file name.
''' </summary>
''' <seealso cref="FileNameEditor"/>
Friend Class IconFileNameEditor : Inherits FileNameEditor

#Region " Constructors "

    ''' <summary>
    ''' Initializes a new instance of the <see cref="IconFileNameEditor"/> class.
    ''' </summary>
    Public Sub New()
        MyBase.New()
    End Sub

#End Region

#Region " Private Methods "

    ''' <summary>
    ''' Initializes the open file dialog when it is created.
    ''' </summary>
    ''' <param name="ofd">
    ''' The <see cref="OpenFileDialog"/> to use to select a file name.
    ''' </param>
    Protected Overrides Sub InitializeDialog(ByVal dlg As OpenFileDialog)
        MyBase.InitializeDialog(dlg)

        With dlg
            .Multiselect = False
            .RestoreDirectory = True
            .DereferenceLinks = True
            .Filter = "Icon Files (*.ico;*.icl;*.exe;*.dll)|*.ico;*.icl;*.exe;*.dll|Icons|*.ico|Libraries|*.dll|Programs|*.exe"
            .FilterIndex = 1
            .SupportMultiDottedExtensions = True
        End With
    End Sub

#End Region

End Class

Для выбора пути к файлу или пути к папке, а также в поиске чего-то уже сделанного и открытого с целью избежать добавления внешних зависимостей в мой проект, я выбрал пользовательский класс FileFolderDialog, предоставленный в этой статьи, и мне удалось написать редактор следующим образом этот:

''' <summary>
''' Provides a user interface for selecting a file or folder name.
''' </summary>
''' <seealso cref="UITypeEditor"/>
Public Class FileOrFolderNameEditor : Inherits UITypeEditor

#Region " Constructors "

    ''' <summary>
    ''' Initializes a new instance of the <see cref="FileOrFolderNameEditor"/> class.
    ''' </summary>
    Public Sub New()
        MyBase.New()
    End Sub

#End Region

#Region " Public Methods"

    ''' <summary>
    ''' Gets the editor style used by the <see cref="UITypeEditor.EditValue(IServiceProvider, Object)"/> method.
    ''' </summary>
    ''' <param name="context">
    ''' An <see cref="ITypeDescriptorContext"/> that can be used to gain additional context information.
    ''' </param>
    ''' <returns>
    ''' A <see cref="UITypeEditorEditStyle"/> value that indicates the style of editor used 
    ''' by the <see cref="UITypeEditor.EditValue(IServiceProvider, Object)"/> method. 
    ''' <para></para>
    ''' If the <see cref="UITypeEditor"/> does not support this method, 
    ''' then <see cref="UITypeEditor.GetEditStyle"/> will return <see cref="UITypeEditorEditStyle.None"/>.
    ''' </returns>
    Public Overrides Function GetEditStyle(ByVal context As ITypeDescriptorContext) As UITypeEditorEditStyle
        Return UITypeEditorEditStyle.Modal
    End Function

    ''' <summary>
    ''' Edits the specified object's value using the editor style indicated by the <see cref="UITypeEditor.GetEditStyle"/> method.
    ''' </summary>
    ''' <param name="context">
    ''' An <see cref="ITypeDescriptorContext"/> that can be used to gain additional context information.
    ''' </param>
    ''' <param name="provider">
    ''' An <see cref="IServiceProvider"/> that this editor can use to obtain services.
    ''' </param>
    ''' <param name="value">
    ''' The object to edit.
    ''' </param>
    ''' <returns>
    ''' The new value of the object. 
    ''' <para></para>
    ''' If the value of the object has not changed, this should return the same object it was passed.
    ''' </returns>
    Public Overrides Function EditValue(ByVal context As ITypeDescriptorContext, ByVal provider As IServiceProvider, ByVal value As Object) As Object

        Using dlg As New OpenFileOrFolderDialog()
            If (dlg.ShowDialog = DialogResult.OK) Then
                Return dlg.SelectedPath
            End If
        End Using

        Return MyBase.EditValue(context, provider, value)

    End Function

#End Region

End Class

Это было довольно легко.

1
Reza Aghaei 29 Май 2019 в 03:39