持久化富文本






4.69/5 (14投票s)
2006年2月14日
4分钟阅读

156353

2409
扩展 RichTextBox 以支持表单持久化和数据绑定。
注意:此控件完全独立。如果您之前下载过,请重新下载,因为我在演示项目中无意中留下了一些第三方引用。
引言
本文的灵感来源于对 Rich Parson 的 RichTextBoxExtended 控件的评论。这是一个非常有用的控件,它包含一个工具栏,可以增强现有的 RichTextBox
控件,使其成为一个文字处理器。
用户的评论非常积极,但人们希望能够通过 Rtf
属性设置富文本控件的内容,以便在表单设计中持久化。其次,对于在运行时编辑内容的情况,可以方便地绑定到 Rtf
属性。本文解释了如何实现这两者,以便您可以轻松构建功能齐全的富文本表单。
次要更改
我对一些与持久化无关的方面做了一些小的修改,希望不会引起争议。
- 我更改了命名空间,使其与控件名称不同,因为这会给最新版本的 C# 带来问题。
- 我为所有属性添加了
DefaultValue
属性,以便除非更改,否则它们不会显示为粗体。 - 我引入了许多额外的属性,这些属性不言自明,例如
ToolBarVisible
、EditorBackColor
和BorderStyle
。 - 我注释掉了允许直接访问内部
RichText
和ToolBar
控件的属性,因为这会破坏封装,并且提供设置相同属性的替代方法会令人困惑并可能导致持久化问题。
注意事项
在使用现有的 RichTextBox
控件时,有两个“功能”可能会让您感到意外。首先,如 Rich 所述,如果在表单初始化之前设置 Rtf
,RichTextBox
控件有时会丢失格式并仅显示纯文本。其次,Rtf
属性存在一个 bug,它有时会在字符串的最后一个字符返回一个空字符。当 RichTextBox
控件的内容较短时,这不会对设计器表单持久化造成任何问题。但是,一旦内容变长,设计器序列化代码就会出现问题,并且会搞砸将字符串分解成多行的工作。(可能这就是 MS 在 Visual Studio 的属性编辑器中默认不提供 Rtf
属性的原因。)这给我带来了不少麻烦,但如果您使用本文随附的 RichTextBoxExtended
,您就不会遇到这些麻烦了。
如何让 Rtf 属性正常工作
为了让 Rtf
属性的消费者能够感知到更改,需要有一个名为 RtfChanged
的属性更改事件。此事件会自动挂钩以处理数据绑定或表单设计器序列化。
我们必须确保在内容更新时触发此事件。最明显的情况是用户直接更新了内容。我们在 Leave
事件处理程序中检查这一点。Rtf
属性可以被直接设置,所以我们在这里也需要触发我们的事件。最后,Rtf
可能会因为 Text
属性的更改而间接更改。
[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);
}
为 Rtf 属性提供属性编辑器
这里有一个令人愉悦的递归,因为 ExtendedRichText
控件用于编辑其自身的 Rtf
属性。
实现属性编辑器是通过向 Rtf
属性添加 Editor
属性来完成的。此属性指定了要调用的 UITypeEditor
。此 UITypeEditor
的实现相当简单,如下所示
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;
}
}
数据绑定和自动绑定
一旦为设计器序列化实现了 Rtf
的持久化,它将自动适用于数据绑定。包含的演示应用程序的图像显示了两个 RichTextExtended
控件 - 一个是只读的,并在表单设计中持久化。另一个是可编辑的,在运行时绑定到 DataSet
并持久化在其中。为了简化示例的安装,此 DataSet
以 XML 格式持久化在文本文件中。在实际应用中,持久化可能会到数据库,并且以这种方式工作得很好。只需确保您的数据库列足够大,因为格式信息会使富文本比您预期的要大。
演示项目中提供了一个独立的解决方案(RichTextExtended.sln)。如果您使用 AgileStudio,还包含了一个解决方案(RichTextBoxExtended2.sln),该解决方案实现了 自动绑定。事实上,我用这个机制非常快速地搭建了演示应用程序。
结论
这个修改后的 RichTextBoxExtended
现在拥有一个属性编辑器,允许您将富文本作为表单设计的一部分进行持久化。它还支持数据绑定,允许在运行时从数据源编辑富文本。现在,您可以不必手动编写 Rtf
赋值就可以快速构建富文本应用程序。
然而,如果您想更进一步,AgileStudio 中的自动绑定将使其真正飞速发展,因为这会自动构建 SQL Server 数据库,并在您将 ExtendedRichText
控件放到表单上时构建存储过程、类型化数据集和绑定。