目前,网上流行的文本编辑器很多,最有名的如:FCKEditor,CuteEditor,FreeTextBox等,当然TextBox也算一个。但是当这么多编辑器放在一块时,我们选择哪一个呢?现在很多软件已经开始尝试做这样的集成了,这里给另外一种思路,让你无限集成你的文本编辑器,而且是可扩展的。
需求:我们的需求是集成各种不同的文本编辑器,让我们的系统在不需要对编辑界面进行再开发的情况下,可以更换编辑器。最好是通过配置的方式进行。
分析:为了实现更改编辑器而不修改代码,我们需要写一个代理控件,这个控件的作用是代理我们的编辑器进行工作。这个代理控件实现我们需要的基本功能,比如:调整大小、设置或获取文本编辑器的内容、设置样式等。因为在统一个系统中,我们对编辑器的要求是一致的,比如我们只需要获取内容,这时我们可以按照我们的要求设计我们的代理控件类(EditorControl)。在实现我们的代理控件前,我们必须解决对特定文本编辑器的访问问题,等我们解决了这一问题后,我们再来实现我们的控件。
下一步我们要来实现我们的代理控件了。我们要让这个代理控件代替各种各样的编辑器,我们就需要有个适配器,让适配器去代替我们访问编辑器控件。我们定义好接口,至于怎么实现,我们留给各个编辑器适配器去实现。我们需要定义一个适配器接口(IEditorAdapter),这个接口需要定义我们在代理控件总必须实现的功能接口。
接下来就改实现这个接口了。对于不同的编辑器,我们需要实现专门的适配器。这样一来,我以后要增加一个编辑器,我只要实现一个这样的适配器就可以了。下面是一个简单的适配器的实现:
好了,我们已经将核心的东西搞定了,下面就是搞定它的扩展性。这里就需要用到工厂模式。我们可以定义一个适配器工厂(EditorAdapterFactory),当我们的代理控件要访问实际的编辑器控件时,我们先通过工厂寻找到适配器,然后通过适配器接口对获取到的适配器进行访问。
这个工厂的目的是通过读取配置文件,获取当前配置的文本编辑器。好了,已经实现了工厂了,对文本编辑器的封装已经完成了,下面我们就该实现我们的代理控件了。
代理控件是一个表示层对文本编辑器调用的统一接口,通过这个代理,任何的文本编辑器都可以被我们的代理控件包容。
基本的框架已经搭建完成,这时工作并没有完全结束,你还需要实现你的文本编辑器适配器。比如:CuteEditorAdapter,FCKEditorAdapter,FreeTextBoxEditorAdapter等等。这时你就不用怕你对各个不同编辑器的需求来烦恼你,甚至当你觉得这个编辑器不好用之后,自己写一个编辑器,实现一个适配器,一切就都OK了。
当然,这里给出的代码只是个DEMO,抛砖引玉。特别是适配器接口还很不完善。以后我建议要设立一个文本编辑器的适配器统一标准,不管谁开发什么样的编辑器,由开发这按照这个标准实现一个适配器,这样我们大家使用时就会很轻松了。
需求:我们的需求是集成各种不同的文本编辑器,让我们的系统在不需要对编辑界面进行再开发的情况下,可以更换编辑器。最好是通过配置的方式进行。
分析:为了实现更改编辑器而不修改代码,我们需要写一个代理控件,这个控件的作用是代理我们的编辑器进行工作。这个代理控件实现我们需要的基本功能,比如:调整大小、设置或获取文本编辑器的内容、设置样式等。因为在统一个系统中,我们对编辑器的要求是一致的,比如我们只需要获取内容,这时我们可以按照我们的要求设计我们的代理控件类(EditorControl)。在实现我们的代理控件前,我们必须解决对特定文本编辑器的访问问题,等我们解决了这一问题后,我们再来实现我们的控件。
下一步我们要来实现我们的代理控件了。我们要让这个代理控件代替各种各样的编辑器,我们就需要有个适配器,让适配器去代替我们访问编辑器控件。我们定义好接口,至于怎么实现,我们留给各个编辑器适配器去实现。我们需要定义一个适配器接口(IEditorAdapter),这个接口需要定义我们在代理控件总必须实现的功能接口。
public
interface
IEditorAdapter
... {
/**//// <summary>
/// Get the text editor control
/// </summary>
/// <returns></returns>
Control GetEditorControl();
/**//// <summary>
/// Get or set the content of the editor control when this control post data.
/// </summary>
/// <returns></returns>
string Content...{get;set;}
/**//// <summary>
/// Get or set the control's width.
/// </summary>
Unit Width ...{ get;set;}
/**//// <summary>
/// Get or set the control's height.
/// </summary>
Unit Height ...{ get;set;}
/**//// <summary>
/// Get or set the control's style.
/// </summary>
string CssClass ...{ get;set;}
/**//// <summary>
/// Get or set the control's ID
/// </summary>
string ControlID ...{ get;set;}
}
... {
/**//// <summary>
/// Get the text editor control
/// </summary>
/// <returns></returns>
Control GetEditorControl();
/**//// <summary>
/// Get or set the content of the editor control when this control post data.
/// </summary>
/// <returns></returns>
string Content...{get;set;}
/**//// <summary>
/// Get or set the control's width.
/// </summary>
Unit Width ...{ get;set;}
/**//// <summary>
/// Get or set the control's height.
/// </summary>
Unit Height ...{ get;set;}
/**//// <summary>
/// Get or set the control's style.
/// </summary>
string CssClass ...{ get;set;}
/**//// <summary>
/// Get or set the control's ID
/// </summary>
string ControlID ...{ get;set;}
}
class
RichTextBoxEditorAdapter : IEditorAdapter
... {
private TextBox editor = null;
public RichTextBoxEditorAdapter()
...{
initControl();
}
void initControl()
...{
editor = new TextBox();
editor.Wrap = true;
}
IEditorAdapter 成员#region IEditorAdapter 成员
public Control GetEditorControl()
...{
return editor;
}
public string Content
...{
get
...{
return editor.Text;
}
set
...{
editor.Text = value;
}
}
public Unit Width
...{
get
...{
return editor.Width;
}
set
...{
editor.Width = value;
}
}
public Unit Height
...{
get
...{
return editor.Height;
}
set
...{
editor.Height = value;
}
}
public string CssClass
...{
get
...{
return editor.CssClass;
}
set
...{
editor.CssClass = value;
}
}
public string ControlID
...{
get
...{
return editor.ID;
}
set
...{
editor.ID = value;
}
}
#endregion
}
... {
private TextBox editor = null;
public RichTextBoxEditorAdapter()
...{
initControl();
}
void initControl()
...{
editor = new TextBox();
editor.Wrap = true;
}
IEditorAdapter 成员#region IEditorAdapter 成员
public Control GetEditorControl()
...{
return editor;
}
public string Content
...{
get
...{
return editor.Text;
}
set
...{
editor.Text = value;
}
}
public Unit Width
...{
get
...{
return editor.Width;
}
set
...{
editor.Width = value;
}
}
public Unit Height
...{
get
...{
return editor.Height;
}
set
...{
editor.Height = value;
}
}
public string CssClass
...{
get
...{
return editor.CssClass;
}
set
...{
editor.CssClass = value;
}
}
public string ControlID
...{
get
...{
return editor.ID;
}
set
...{
editor.ID = value;
}
}
#endregion
}
好了,我们已经将核心的东西搞定了,下面就是搞定它的扩展性。这里就需要用到工厂模式。我们可以定义一个适配器工厂(EditorAdapterFactory),当我们的代理控件要访问实际的编辑器控件时,我们先通过工厂寻找到适配器,然后通过适配器接口对获取到的适配器进行访问。
/**/
/// <summary>
/// The factory of editor adapter.
/// </summary>
public class EditorAdapterFactory
... {
private static readonly ILog log = LogManager.GetLogger(typeof(EditorAdapterFactory));
/**//// <summary>
/// Get the text editor adapter
/// </summary>
/// <returns></returns>
public static IEditorAdapter GetAdapter()
...{
try
...{
string typeName = Configuration.Configuration.editorAdapterConfiguration.getAdapterTypeName();
if (string.IsNullOrEmpty(typeName))
...{
return getDefaultEditor();
}
else
...{
Type t = Type.GetType(typeName);
if (t == null) return getDefaultEditor();
else
...{
if (t.GetInterface("IEditorAdapter") != null)
...{
log.Info("Get editor adapter:" + t.FullName);
return (IEditorAdapter)Activator.CreateInstance(t);
}
else
...{
log.Error("System can't find a adapter that implement the interface IEditorAdapter");
throw new Exception("配置的编辑器适配器没有实现IEditorAdapter接口.");
}
}
}
}
catch (Exception ex)
...{
log.Error(ex);
return getDefaultEditor();
}
}
//其它代码。
}
/// The factory of editor adapter.
/// </summary>
public class EditorAdapterFactory
... {
private static readonly ILog log = LogManager.GetLogger(typeof(EditorAdapterFactory));
/**//// <summary>
/// Get the text editor adapter
/// </summary>
/// <returns></returns>
public static IEditorAdapter GetAdapter()
...{
try
...{
string typeName = Configuration.Configuration.editorAdapterConfiguration.getAdapterTypeName();
if (string.IsNullOrEmpty(typeName))
...{
return getDefaultEditor();
}
else
...{
Type t = Type.GetType(typeName);
if (t == null) return getDefaultEditor();
else
...{
if (t.GetInterface("IEditorAdapter") != null)
...{
log.Info("Get editor adapter:" + t.FullName);
return (IEditorAdapter)Activator.CreateInstance(t);
}
else
...{
log.Error("System can't find a adapter that implement the interface IEditorAdapter");
throw new Exception("配置的编辑器适配器没有实现IEditorAdapter接口.");
}
}
}
}
catch (Exception ex)
...{
log.Error(ex);
return getDefaultEditor();
}
}
//其它代码。
}
[Designer(
typeof
(Design.EditorControlDesign))]
public class EditorControl : Control
... {
private Control control;
private IEditorAdapter adapter = null;
public EditorControl()
...{
adapter = getAdapter();
control = adapter.GetEditorControl();
this.Controls.Add(control);
}
/**//// <summary>
/// Get the text editor from the configuration
/// </summary>
/// <returns></returns>
private Control getControl(IEditorAdapter adapter)
...{
return adapter.GetEditorControl();
}
/**//// <summary>
/// Get the editor adapter
/// </summary>
/// <returns></returns>
private IEditorAdapter getAdapter()
...{
return EditorAdapterFactory.GetAdapter();
}
protected override void Render(HtmlTextWriter writer)
...{
}
public override void RenderControl(HtmlTextWriter writer)
...{
control.RenderControl(writer);
}
public string Content
...{
get ...{ return adapter.Content; }
set ...{ adapter.Content = value; }
}
public Unit Width
...{
get ...{ return adapter.Width; }
set ...{ adapter.Width = value; }
}
public Unit Height
...{
get ...{ return adapter.Height; }
set ...{ adapter.Height = value; }
}
public string CssClass
...{
get ...{ return adapter.CssClass; }
set ...{ adapter.CssClass = value; }
}
}
public class EditorControl : Control
... {
private Control control;
private IEditorAdapter adapter = null;
public EditorControl()
...{
adapter = getAdapter();
control = adapter.GetEditorControl();
this.Controls.Add(control);
}
/**//// <summary>
/// Get the text editor from the configuration
/// </summary>
/// <returns></returns>
private Control getControl(IEditorAdapter adapter)
...{
return adapter.GetEditorControl();
}
/**//// <summary>
/// Get the editor adapter
/// </summary>
/// <returns></returns>
private IEditorAdapter getAdapter()
...{
return EditorAdapterFactory.GetAdapter();
}
protected override void Render(HtmlTextWriter writer)
...{
}
public override void RenderControl(HtmlTextWriter writer)
...{
control.RenderControl(writer);
}
public string Content
...{
get ...{ return adapter.Content; }
set ...{ adapter.Content = value; }
}
public Unit Width
...{
get ...{ return adapter.Width; }
set ...{ adapter.Width = value; }
}
public Unit Height
...{
get ...{ return adapter.Height; }
set ...{ adapter.Height = value; }
}
public string CssClass
...{
get ...{ return adapter.CssClass; }
set ...{ adapter.CssClass = value; }
}
}
基本的框架已经搭建完成,这时工作并没有完全结束,你还需要实现你的文本编辑器适配器。比如:CuteEditorAdapter,FCKEditorAdapter,FreeTextBoxEditorAdapter等等。这时你就不用怕你对各个不同编辑器的需求来烦恼你,甚至当你觉得这个编辑器不好用之后,自己写一个编辑器,实现一个适配器,一切就都OK了。
当然,这里给出的代码只是个DEMO,抛砖引玉。特别是适配器接口还很不完善。以后我建议要设立一个文本编辑器的适配器统一标准,不管谁开发什么样的编辑器,由开发这按照这个标准实现一个适配器,这样我们大家使用时就会很轻松了。