基于 Windows 窗体的 HTML 输出文本编辑器






4.91/5 (165投票s)
一款基于 Windows Forms 的文本编辑器,可输出 HTML,通过在编辑模式下使用浏览器控件实现。
通知:截至 2017 年 10 月 28 日,已有新版本可用。
包含以下功能
- 需要 .NET 4.5.1。
- 修复了导致浏览器对话框弹出的“另存为”和“加载”错误。
- 通过 URL 或文件系统插入内嵌图像。文件系统图像将嵌入到生成的 HTML 中。
- 完全支持对 HTML、Body HTML、Body Text 的编程访问
- 设置 body 的背景颜色。
- 插入图像。
- 调整图像大小。
- 从文本添加和编辑超链接。
- 从图像添加和编辑超链接。
- 支持从 Windows XP SP2 到 Windows 8。
- 支持所有版本的 IE。
引言
不久前,我正在开发一个聊天应用程序,其中一个聊天客户端是基于 Web 的,用 ASP.NET 2.0 编写。另一个聊天客户端是使用 C# 编写的基于 Windows Forms 的 .NET 应用程序。我的 WinForms 客户端需要一个可以输出 HTML 的富文本编辑器,以便 ASP.NET 客户端可以显示 WinForms 客户端的格式。在使用 RTF 文本框时,这一点被排除了。
我找到的解决方案是,在我的 WinForms 客户端中使用处于编辑模式的 `WebBrowser` 控件。浏览器上方工具栏上的格式按钮会与 `WebBrowser` 控件中的当前选区同步。
本文解释了从 `WebBrowser` 控件构建编辑器控件过程中遇到的许多问题的解决方案。我不会深入介绍所有内容,因为源代码本身并不难浏览。但是,我确实涵盖了一些使其正常工作的必要技巧。
使用控件
该控件是一个可执行文件。
您可以直接运行其主窗体,也可以将其作为控件嵌入到您自己的应用程序中。
要将其嵌入到您自己的应用程序中,只需在 Visual Studio 中像引用 DLL 一样引用该 EXE 即可。
它应该会出现在 Visual Studio 的工具箱窗口中。
请查看源代码,了解如何从您的代码中访问它的示例。
它是一个 .NET 2.0 控件,因此应该可以在旧项目中运行。
设置设计模式
在使用该组件时,会自动应用设计模式并为文档建立编辑模板。但为了参考,这里简要解释一下它的工作原理。
应用设计模式需要使用 COM 接口:添加对“Microsoft HTML Object Library”的引用,该引用解析为 MSHTML,并添加对“MSHTML”的“using”。
在应用更改到 DOM 文档之前,必须向控件添加一个 body。为此,您可以简单地将一些文本应用于 `WebBrowser` 控件的 `DocumentText` 属性。
webBrowser1.DocumentText = "<html><body></body></html>"
接下来,获取对新的 `DomDocument` COM 接口的引用,并将设计模式设置为“`On`”。
IHTMLDocument2 doc =
webBrowser1.Document.DomDocument as IHTMLDocument2;
doc.designMode = "On";
最后,我替换了浏览器控件的上下文菜单,以避免显示默认的 IE 浏览器上下文菜单。
webBrowser1.Document.ContextMenuShowing +=
new HtmlElementEventHandler(Document_ContextMenuShowing);
浏览器现在处于设计模式,并提供了一个自定义方法来显示上下文菜单。
应用格式
您可以使用 `browser.Document` 上的 **`ExecCommand`** 方法,向处于设计模式下的浏览器控件应用格式和编辑器功能。
这里有一些例子
public void Cut()
{
webBrowser1.Document.ExecCommand("Cut", false, null);
}
public void Paste()
{
webBrowser1.Document.ExecCommand("Paste", false, null);
}
public void Copy()
{
webBrowser1.Document.ExecCommand("Copy", false, null);
}
一些命令将切换当前选区的格式状态。
public void Bold()
{
webBrowser1.Document.ExecCommand("Bold", false, null);
}
public void Italic()
{
webBrowser1.Document.ExecCommand("Italic", false, null);
}
同步格式按钮与选中文本
这比向浏览器控件应用格式命令要棘手一些。我每 200 毫秒实际查询一次浏览器编辑器选区状态,并基于此设置工具栏格式按钮。
private void timer_Tick(object sender, EventArgs e)
{
SetupKeyListener();
boldButton.Checked = IsBold();
italicButton.Checked = IsItalic();
underlineButton.Checked = IsUnderline();
orderedListButton.Checked = IsOrderedList();
unorderedListButton.Checked = IsUnorderedList();
linkButton.Enabled = SelectionType == SelectionType.Text;
UpdateFontComboBox();
UpdateFontSizeComboBox();
if (Tick != null) Tick();
}
您会注意到有一个 `Tick` 事件,该事件在计时器 `tick` 事件结束时触发。外部组件可以订阅此事件来更新其 GUI 的状态。例如,它们可以根据编辑器控件的状态更新剪切/复制/粘贴/撤销/重做按钮的 `Enabled` 状态。
我通过使用从 `WebBrowser` 控件检索到的 COM 文档接口来实现此目的
IHTMLDocument2 doc = webBrowser1.Document.DomDocument as IHTMLDocument2;
然后我使用 **`queryCommandState`** 来确定当前选区的状态
public bool IsBold()
{
return doc.queryCommandState("Bold");
}
public bool IsItalic()
{
return doc.queryCommandState("Italic");
}
public bool IsUnderline()
{
return doc.queryCommandState("Underline");
}
链接按钮和字体控件以类似的方式管理,但我将把这个留给您在代码中查看。
焦点
控件的焦点也不是那么简单。`WebBrowser` 控件本身不会接受焦点。`WebBrowser` 控件的文档也不会。**但是**,如果控件中存在 `body` 元素,则 `body` 会获得焦点。
private void SuperFocus()
{
if (webBrowser1.Document != null &&
webBrowser1.Document.Body != null)
webBrowser1.Document.Body.Focus();
}
当然,您永远不需要直接调用此方法。调用控件上的 **`Focus`** 方法会将焦点放在包含 `WebBrowser` 控件的编辑器控件上。当编辑器控件收到 **`GotFocus`** 事件时,它会自动将焦点转移到 `WebBrowser` 的文档 body。
检索文本或 HTML
**`BodyHtml`** 和 **`BodyText`** 方法分别检索 body 的 HTML 和文本。
链接到组件程序集
在 Visual Studio 2005 中,您可以链接到一个程序集(添加引用),即使该程序集是可执行文件。该编辑器是作为一个嵌入在窗体中的组件编写的,因此您可以将其添加到控件面板,并将其拖放到您的应用程序中。该控件的名称是 `Editor`,位于 `Design` 命名空间下。
结论
基于 .NET 2.0 的 `WebBrowser` 控件可以有效地用作文本编辑器。当您需要一个可以用作 HTML 编辑器的编辑器控件时,这非常有用。在某些方面,实现并非完全直接。本文试图展示一些使其正常工作的必要技巧。
历史
- 2006 年 10 月 4 日 - 各种错误修复和设计更新/设计器支持。
- 2006 年 10 月 19 日 - 更多错误修复和更多设计器支持。
- 2017 年 10 月 28 日 - 升级到 .net 4.5.1 和 VS 2015