В Windows Forms я представляю пользовательский класс в элементе управления PropertyGid
, который имеет различные строковые свойства, как вы можете заметить на следующем изображении:
Проблема в том, что я не полностью удовлетворен текущим поведением при изменении значения строковых свойств. Для тех свойств, которые ожидают путь к файлу или каталогу, таких как свойства «Цель» или «Рабочий каталог», я хотел бы знать, возможно ли и целесообразно реализовать TypeConverter / Type Descriptor, который открывал бы OpenFileDialog
при нажатии в стрелка вниз справа от поля в сетке свойств. То есть, чтобы выбрать файл или папку через OpenFileDialog
, вместо того, чтобы напрямую писать путь в сетке свойств, но при этом оставить возможность напрямую написать путь, если я хочу это сделать.
Может быть, библиотека классов .NET Framework уже предоставляет TypeConverter/TypeDescriptor, который я запрашиваю? Если нет, то возможно ли это сделать? И как начать это делать?
Или любая другая идея, чтобы иметь возможность открыть OpenFileDialog
, чтобы изменить значение определенного свойства в элементе управления PropertyGrid
?.
@Hans Passant Спасибо за комментарий. Я начну с практики на примере кода по адресу: docs.microsoft.com/en-us/dotnet/api/system.drawing.design.uitypeeditor?view=netframework-4.8, но отмечу, что эти свойства имеют строковый тип данных.
По-видимому, есть встроенный UITypeEditor с именем класса FileNameEditor, который может делать то, что мне нужно, или, по крайней мере, это то, что предлагается здесь: stackoverflow.com/a/2373374/1248295. Я еще не пробовал.
Этот редактор открывает стандартный диалог выбора файлов (Открыть файл) и позволяет выбрать путь/имя файла.
В моем приложении у меня есть свойство, которое принимает путь к файлу значка, другое свойство, которое может принимать файл или папку, и другое свойство, которое принимает путь к папке.
Итак, мне пришлось написать варианты для каждого из этих свойств...
Самый простой, и в случае, если вас устраивает внешний вид FolderBrowserDialog
и ограничения, это напрямую указать класс System.Windows.Forms.Design.FolderNameEditor
в классе EditorAttribute
. В остальном Ооки.Диалоги — хорошая библиотека с открытым исходным кодом в качестве альтернативы для получения современного диалогового окна.
Второй самый простой — это редактор для выбора пути к файлу иконки:
''' <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
Это было вообще легко.
Существуют встроенные редакторы типов пользовательского интерфейса FileNameEditor
и 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";
}
}
Фреймворк ничего не знает об IShellLink. Создайте модальный UITypeEditor для настройки редактирования значений.