Click here to Skip to main content
Click here to Skip to main content

Handy Type Editors: Customizable Filename Editor

, 22 Apr 2004
Rate this:
Please Sign up or sign in to vote.
Making use of .NET design capabilities by implementing filename type editor.

Demo snapshot

Introduction

One of the great features that the .NET framework has is the developer's ability to control the way the types are designed. While all the basic types are supplied with their own default editors, some of the types are used for variety of purposes, and a generalized editor is not always convenient enough.

Storing a filename string, either with full or relative path is quite a frequent need. Oddly, FileNameEditor class supplies only generic non-modifiable file name dialog. To assign your own title or filter, one must inherit it (oddly, no Filter or Title property is supplied). But it is not a big deal as we'll build one in a matter of minutes.

Background: Crash Course on Type Editors

Type editors are invoked when altering an object from a GUI like PropertyGrid control, or its numerous clones. Every row contains a name of a property and its value, which can or cannot be edited. If a type editor is associated with the property, usually an ellipsis or a drop-down button appears in the value cell. Same type editors though leave the cell as it is. .NET 1.1 has 3 kinds of editors (or "styles", by MS terms):

  1. Modal editor which is invoked by pressing the ellipsis button. It is intended to show a modal form, however, it is up to its developer how exactly it works. In the UITypeEditorEditStyle enumeration, this style is associated with UITypeEditorEditStyle.Modal.
  2. Drop-down editor. It is expected that the developer will create a control which will be shown just below the cell. The width of the control is automatically justified to match the width of the value cell. In the UITypeEditorEditStyle enumeration, this style is associated with UITypeEditorEditStyle.DropDown.
  3. Free input editor. Normally, no interactive GUI should be used here. In the UITypeEditorEditStyle enumeration, this style is associated with UITypeEditorEditStyle.None.

To write a fully functional type editor, two methods must be overridden: GetEditStyle and EditValue. The former determines the style of the editor, while the latter is invoked when the GUI is activated by user. The returned value is assigned to the property being edited.

Let's Code!

Now, when we know how it works, let's get started. Since it is natural for the filename editor to open a file dialog which is a modal window, our editor has Modal style:

Public Overloads Overrides Function GetEditStyle(ByVal context As _
                    ITypeDescriptorContext) As UITypeEditorEditStyle
    If Not context Is Nothing AndAlso Not context.Instance Is Nothing Then
        Return UITypeEditorEditStyle.Modal
    End If
    Return UITypeEditorEditStyle.None
End Function

The next method to implement will be EditValue. For now, we'll just create an OpenFileDialog and show it to the user:

Public Overloads Overrides Function EditValue( _
                ByVal context As ITypeDescriptorContext, _
                ByVal provider As System.IServiceProvider, _
                ByVal value As [Object]) As [Object]
    If context Is Nothing OrElse provider Is Nothing _
                OrElse context.Instance Is Nothing Then
        Return MyBase.EditValue(provider, value)
    End If

    Dim fileDlg As New OpenFileDialog
    fileDlg.FileName = value
    fileDlg.Title = "Select " & context.PropertyDescriptor.DisplayName
    fileDlg.Filter = "All Files (*.*)|*.*"
    If fileDlg.ShowDialog() = DialogResult.OK Then
        value = fileDlg.FileName
    End If
    fileDlg.Dispose()
    Return value
End Function

That's it! Ready to go.

Using the code

To use the class, bind it to your property like this:

<Editor(GetType(UIFilenameEditor), GetType(UITypeEditor))> _
Property MyFilename() As String

Bells and Whistles

Isn't it all too simplistic? I mean, browsing through all the files, always in the "open file" mode... Certainly, there is room for improvement. The problem is, there is no way to pass these parameters from the class to the editor, because the Editor attribute receives only the type rather than instance. There are ways to solve this problem though.

One, less elegant, is using the editor's Context.Instance to obtain the reference to the object being edited, and then setting the dialog's specifications from the object's members (possibly outlined by a special interface). This is not good - we have to mix the design layer with the class.

The other way is making use of additional attributes. The user might use or not use these attributes. This is the preferable way of passing the parameters to the editor.

Writing attribute classes is very simple. There are only two requirements:

  1. Your class must inherit the Attribute class.
  2. The name of your class must end with the string "Attribute". (Yes, I don't understand why either.)

What attributes do we need? It would be neat to be able to specify the extensions to look for (the filter), and whether to show save file dialog rather than open file dialog.

The simple one first.

<AttributeUsage(AttributeTargets.Property)> _
Public Class SaveFileAttribute
    Inherits Attribute
End Class

That's it! Note the AttributeUsage attribute (hmm...). It is not compulsory, but it is good for the sanity check: specifying where your attribute class is valid.

To use your attribute, bind it to your property like this:

<Editor(GetType(UIFilenameEditor), GetType(UITypeEditor)), SaveFile> _
Property MyFilename() As String

Now, we'll create the filter attribute. As we need it to hold a parameter, we also need to provide a respective data member and a parameter, like this:

<AttributeUsage(AttributeTargets.Property)> _
Public Class FileDialogFilterAttribute
    Inherits Attribute
    Private _filter As String

    Public ReadOnly Property Filter() As String
        Get
            Return Me._filter
        End Get
    End Property

    Public Sub New(ByVal filter As String)
        MyBase.New()
        Me._filter = filter
    End Sub
End Class

Again, not very sophisticated. As you can see, the constructor is overridden - this is the way to pass the data to an attribute.

To use your attribute, bind it to your property like this:

<Editor(GetType(UIFilenameEditor), GetType(UITypeEditor)), _
    SaveFile, _
    FileDialogFilter("Text files (*.txt)|*.txt|All files (*.*)|*.*")> _
Property MyFilenameWhichIWantToUseForATextFileToSave() As String

We've done with the attributes, but now we must make use of them. For this, we'll modify the EditValue method in the UIFilenameEditor class:

Public Overloads Overrides Function EditValue( _
                ByVal context As ITypeDescriptorContext, _
                ByVal provider As System.IServiceProvider, _
                ByVal value As [Object]) As [Object]
    If context Is Nothing OrElse provider Is Nothing _
                OrElse context.Instance Is Nothing Then
        Return MyBase.EditValue(provider, value)
    End If

    Dim fileDlg As FileDialog
    If context.PropertyDescriptor.Attributes(GetType(SaveFileAttribute))_
                                                         Is Nothing Then
        fileDlg = New OpenFileDialog
    Else
        fileDlg = New SaveFileDialog
    End If
    fileDlg.Title = "Select " & context.PropertyDescriptor.DisplayName
    fileDlg.FileName = value

    Dim filterAtt As FileDialogFilterAttribute = _
        context.PropertyDescriptor.Attributes(GetType(FileDialogFilterAttribute))
    If Not filterAtt Is Nothing Then fileDlg.Filter = filterAtt.Filter
    If fileDlg.ShowDialog() = DialogResult.OK Then
        value = fileDlg.FileName
    End If
    fileDlg.Dispose()
    Return value
End Function

As you can guess, these context.PropertyDescriptor.Attributes(GetType(MyAttribute)) clauses fetch the attribute of the specified type, if there's any. It is also the way to check if the attribute is specified.

That's it. Enjoy! Next time - more handy type editors.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author


Comments and Discussions

 
GeneralMy vote of 5 PinmemberNiyazi Yarar5-Dec-10 7:40 
QuestionAbility to replace basedir with tilde (~) ? Pinmembergbrugiere26-Apr-07 3:55 
AnswerRe: Ability to replace basedir with tilde (~) ? PinmemberTodd Thompson17-May-13 7:49 
GeneralGet reference to the property-grid control Pinmemberywchen8-Mar-05 7:46 
GeneralRe: Get reference to the property-grid control PinmemberVadimBerman8-Mar-05 9:24 
GeneralRe: Get reference to the property-grid control Pinmemberywchen11-Mar-05 13:48 
GeneralRe: Get reference to the property-grid control PinmemberVadimBerman11-Mar-05 20:50 
GeneralRe: Get reference to the property-grid control Pinmemberywchen12-Mar-05 8:16 
GeneralRe: Get reference to the property-grid control PinmemberVadimBerman12-Mar-05 20:58 
GeneralRe: Get reference to the property-grid control Pinmemberywchen13-Mar-05 7:09 
GeneralRe: Get reference to the property-grid control Pinmemberywchen13-Mar-05 7:56 
GeneralRe: Get reference to the property-grid control PinmemberVadimBerman13-Mar-05 21:28 
GeneralRe: Get reference to the property-grid control Pinmemberywchen14-Mar-05 18:44 
GeneralRe: Get reference to the property-grid control PinmemberVadimBerman14-Mar-05 21:08 
AnswerRe: Get reference to the property-grid control [modified] Pinmembermaltwhiskman19-May-12 1:31 
GeneralOr alternatively... PinsussAllan Yuill23-Apr-04 6:25 
GeneralRe: Or alternatively... PinsussCraig Eddy23-Apr-04 12:00 
GeneralRe: Or alternatively... PinmemberVadimBerman23-Apr-04 22:10 
GeneralRe: Or alternatively... PinmemberVadimBerman23-Apr-04 22:08 
GeneralRe: Or alternatively... Pinmemberkillers3-May-04 18:40 
GeneralRe: Or alternatively... PinmemberVadimBerman3-May-04 20:00 
GeneralRe: Or alternatively... Pinmemberkillers4-May-04 2:17 
GeneralRe: Or alternatively... Pinmemberkillers4-May-04 3:48 
GeneralRe: Or alternatively... Pinmemberkillers4-May-04 3:49 
GeneralRe: Or alternatively... PinmemberVadimBerman4-May-04 20:46 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.1411023.1 | Last Updated 23 Apr 2004
Article Copyright 2004 by VadimBerman
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid