Replace It
Some of the RichTextBox properties just don’t make sense for XEditor. Others don’t work with a simple pass-through strategy. And still others can be improved. As an example, consider the FileName property.
The RichTextBox control has two ways to load the contents of a file into the control. You can set the FileName property or you can call the LoadFile method. The LoadFile method has a parameter that specifies whether to load the file in text or in RTF format, but design-time properties can’t have parameters. This leads to some confusion. You can’t control how a file is loaded if you use the FileName property, but you can’t load at design time with the LoadFile method.
My solution is that XEditor has both a design-time-only FileName property and a run-time-only LoadFile method, and that the FileName property actually uses the LoadFile method. I maintain my own internal variable for the complete file path and never use the FileName property of the delegated RichTextBox control. In addition, I provide a read-only FilePath property that returns the full path of the file. (FileName returns only the base and extension.) In other words, I provide most of the same functionality, but with a different architecture. Let’s take a look.
I start with a private sFilePath variable. It contains either an empty string, if the contents of the control did not come from a file, or the full path of the current file. Any code that can load a new file must ensure that this variable is always valid. Here’s how the FileName and FilePath properties deal with sFilePath:
' Read-only, run-time only
Property Get FilePath() As String
FileName = sFilePath
End Property
' Run time or design time
Property Get FileName() As String
If sFilePath <> sEmpty Then FileName = GetFileBaseExt(sFilePath)
End Property
' Design-time only (use LoadFile at run time)
Property Let FileName(sFileNameA As String)
If Ambient.UserMode Then ErrRaise eeSetNotSupportedAtRuntime
' Can't pass through design-time errors
On Error GoTo FailFileName
If sFileNameA = sEmpty Then
' Empty text only if it comes from a file
If sFilePath <> sEmpty Then Text = sEmpty
sFilePath = sEmpty
Else
sFileNameA = GetFullPath(sFileNameA)
LoadFile sFileNameA
sFilePath = sFileNameA
End If
PropertyChanged "FileName"
Exit Property
FailFileName:
' Could empty FileName and Text, but I choose to ignore them
End Property
The Property Get procedures simply return the variable in the appropriate format. First, the Property Let uses the Ambient.UserMode property to prevent run-time changes. Then it deals with the three possibilities: an empty string, a valid filename, and an invalid filename. Notice that actual loading of files is deferred to the LoadFile method shown below:
‘ Run-time only (use FileName at design time)
Sub LoadFile(sFileNameA As String, _
Optional ordTextModeA As ELoadSave = elsDefault)
If sFileNameA = sEmpty Then Exit Sub
BugAssert ordTextModeA >= elsDefault And ordTextModeA <= elstext
If ordTextModeA = elsDefault Then
ordTextModeA = IIf(TextMode, elstext, elsrtf)
End If
If TextMode Then Set Font = fontDefault
‘ Don’t reload clean file
sFileNameA = GetFullPath(sFileNameA)
If sFileNameA = sFilePath And DirtyBit = False Then Exit Sub
‘ Use RichTextBox method (raise unhandled errors to caller)
txt.LoadFile sFileNameA, ordTextModeA
sFilePath = sFileNameA
DirtyBit = False
End Sub
This method uses the LoadFile property of the delegated RichTextBox control. The code uses the TextMode and DirtyBit properties, which I’ll discuss shortly. Unlike the FileName property, this function lets unhandled errors pass through to the caller (which might be the FileName property). Methods are always
run-time-only, but this one can be called by a design-time-only property. The SaveFile method works much the same as LoadFile. XEditor has other properties that can change the filename, but they all work by calling LoadFile or SaveFile.