Note: This control is totally standalone. If you've downloaded it before, please do again as I accidenly left some third party references in the demo project.
Introduction
This article was prompted by comments about Rich Parson's RichTextBoxExtended Control. This is a very useful control that includes a tool bar to augment the existing RichTextBox
control into a word processor.
The comments from users were very positive, but there was a desire to be able to set the content of a rich text control via the Rtf
property so it can be persisted in the form design. Secondly, for cases where the content is being edited at runtime, it makes sense to be able to data bind to the Rtf
property. This article explains how to do both of these so you can build fully functional Rich Text forms with a minimum of effort.
Minor Changes
I made a few minor changes unconnected with persistence that I hope won't be controversial.
- I changed the namespace so it has a different name from the control, as this will cause problems with the latest version of C#.
- I added
DefaultValue
attributes to all the properties so they don't show up bold unless changed.
- I introduced a number of additional properties which are self explanatory, such as
ToolBarVisible
, EditorBackColor
, and BorderStyle
.
- I've commented out the properties, allowing direct access to the internal
RichText
and ToolBar
controls, as this breaks the encapsulation, and providing alternative methods for setting the same property is confusing and can cause persistence issues.
Gotyas
When working with the existing RichTextBox
control, there are two "features" that can catch you out. Firstly, as mentioned by Rich, if you set Rtf
before the form initialization, the RichTextBox
control will sometimes lose its formatting and just display plain text. Secondly, there is a bug in the Rtf
property where it sometimes returns a null character as the very last character in the string. This causes no problems with designer form persistence when the RichTextBox
control has a short content. However, once the content gets longer, the designer serialization code has a nervous breakdown and messes up the job of breaking the string into multiple lines. (Possibly, this is why MS made the Rtf
property unavailable as standard in the property editor in Visual Studio.) This caused me more than a little bit of grief but it needn't cause you any if you use the RichTextBoxExtended
included with this article.
How to get the Rtf property to work
In order for consumers of the Rtf
property to be aware of changes, there needs to be a property change event called RtfChanged
. This event will automatically be hooked to handle data binding or form designer serialization.
We must ensure that this event is triggered whenever the content has been updated. The obvious case is when the user has updated the content directly. This, we check in a Leave
event handler. The Rtf
property may be set directly so we need to trigger our event here also. Finally, Rtf
could change indirectly as a result of a change to the Text
property.
[Category("Property Changed")]
public event EventHandler RtfChanged;
[
System.ComponentModel.Description("Contents in Rtf format"),
RecommendedAsConfigurable(true),
Category("Data"),
Bindable(true),
Editor(typeof(Design.RichTextBoxExtendedEditor),
typeof(System.Drawing.Design.UITypeEditor))
]
public string Rtf
{
get
{ return rtb1.Rtf;
}
set
{ rtb1.Rtf= value;
if (RtfChanged!=null)
RtfChanged(this,EventArgs.Empty);
}
}
#endregion
private void rtb1_TextChanged(object sender, System.EventArgs e)
{
if (RtfChanged!=null)
RtfChanged(this,EventArgs.Empty);
}
private void rtb1_Leave(object sender, System.EventArgs e)
{
if (this.rtb1.Modified && RtfChanged!=null)
RtfChanged(this,EventArgs.Empty);
}
Providing a Property Editor for the Rtf Property
There's a pleasing recursion here, as the ExtendedRichText
control is used to edit its own Rtf
property.
Implementing a property editor is accomplished by adding the Editor
attribute to the Rtf
property. This attribute specifies which UITypeEditor
to invoke. The implementation of this UITypeEditor
is fairly simple as shown below:
class RichTextBoxExtendedRtfEditor:System.Drawing.Design.UITypeEditor
{
public override System.Drawing.Design.UITypeEditorEditStyle
GetEditStyle(ITypeDescriptorContext context)
{
if (context==null)
return base.GetEditStyle(null);
return System.Drawing.Design.UITypeEditorEditStyle.Modal;
}
public override object EditValue(ITypeDescriptorContext context,
IServiceProvider provider, object value)
{
if (context!=null && provider!=null)
{
IWindowsFormsEditorService edSrv=
(IWindowsFormsEditorService)
provider.GetService(typeof(IWindowsFormsEditorService));
if (edSrv!=null)
{
RichTextBoxExtendedRtfEditorForm dialog=
new RichTextBoxExtendedRtfEditorForm();
if (value is String)
dialog.Value= (string)value;
if (edSrv.ShowDialog(dialog)==
System.Windows.Forms.DialogResult.OK)
value= dialog.Value;
dialog.Dispose();
dialog= null;
}
}
return value;
}
}
Data Binding and Automatic Binding
Once persistence of Rtf
has been implemented for designer serialization, it will automatically work for data binding. The image of the included demo application shows two RichTextExtended
controls - one is read only and is persisted in the form design. The other is editable and is data bound and persisted in a DataSet
at runtime. To keep the sample simple to install, this DataSet
is persisted in a text file as XML. In a real world application, persistence would probably be to a database and it works fine this way. Just make sure your database columns are large enough as the formatting information makes rich text bigger than you might expect.
A standalone solution (RichTextExtended.sln) has been provided in the demo project. If you use AgileStudio, a solution has also been included (RichTextBoxExtended2.sln) that implements automatic binding. In fact, I used this mechanism to knock together the demo app really quickly.
Conclusion
This modified RichTextBoxExtended
now has a property editor to allow you to persist Rich Text as part of the form design. It also supports data binding to allow the editing of Rich Text from a data source at runtime. Now, you can knock together rich text apps without having to hand code your Rtf
assignments.
However, if you want to go one step further, the automatic binding in AgileStudio makes it really fly as this automatically builds the SQL Server database and builds the stored procedures, typed datasets, and bindings when you just drop the ExtendedRichText
control on the form.