[TemplatePart(Name = "PART_Editor", Type = typeof(TextBox))]
[TemplatePart(Name = "PART_View", Type = typeof(TextBlock))]
[TemplateVisualState(Name = "Edit", GroupName = "CommonStates")]
[TemplateVisualState(Name = "View", GroupName = "CommonStates")]
public class EditorBox : Control
{
public const string PART_Editor = "PART_Editor";
public const string PART_View = "PART_View";
public const string VisualState_Edit = "Edit";
public const string VisualState_View = "View";
/// <summary>
/// 模式
/// </summary>
public enum Mode
{
/// <summary>
/// 查看模式
/// </summary>
View,
/// <summary>
/// 编辑模式
/// </summary>
Edit
}
#region Private Fields
private TextBox _editor;
private TextBlock _viewer;
#endregion
#region Dependency Properties
/// <summary>
/// 文本格式集合
/// </summary>
public TextFormatCollection TextFormats
{
get { return (TextFormatCollection)GetValue(TextFormatsProperty); }
set { SetValue(TextFormatsProperty, value); }
}
public static readonly DependencyProperty TextFormatsProperty =
DependencyProperty.Register("TextFormats", typeof(TextFormatCollection), typeof(EditorBox), new PropertyMetadata(new PropertyChangedCallback(OnTextFormatsChanged)));
/// <summary>
/// 文本
/// </summary>
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(EditorBox), new PropertyMetadata(string.Empty));
/// <summary>
/// 是否允许编辑
/// </summary>
public bool CanEdit
{
get { return (bool)GetValue(CanEditProperty); }
set { SetValue(CanEditProperty, value); }
}
public static readonly DependencyProperty CanEditProperty =
DependencyProperty.Register("CanEdit", typeof(bool), typeof(EditorBox), new PropertyMetadata(true));
/// <summary>
/// 当前模式
/// </summary>
public Mode CurrentMode
{
get { return (Mode)GetValue(CurrentModeProperty); }
set { SetValue(CurrentModeProperty, value); }
}
public static readonly DependencyProperty CurrentModeProperty =
DependencyProperty.Register("CurrentMode", typeof(Mode), typeof(EditorBox), new PropertyMetadata(Mode.View, new PropertyChangedCallback(OnCurrentModeChanged)));
#region Property Change Handler
private static void OnTextFormatsChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
(obj as EditorBox).OnTextFormatsChanged(e.OldValue as TextFormatCollection, e.NewValue as TextFormatCollection);
}
/// <summary>
/// 文本格式设置改变时,重新计算文本格式
/// </summary>
/// <param name="oldCollection"></param>
/// <param name="newCollection"></param>
protected virtual void OnTextFormatsChanged(TextFormatCollection oldCollection, TextFormatCollection newCollection)
{
if (oldCollection != null)
{
oldCollection.CollectionChanged -= new NotifyCollectionChangedEventHandler(TextFormats_CollectionChanged);
}
if (newCollection != null)
{
newCollection.CollectionChanged += new NotifyCollectionChangedEventHandler(TextFormats_CollectionChanged);
}
//集合改变时重新计算文本格式
ProcessTextFormat();
}
/// <summary>
/// 集合项改变时,重新计算文本格式
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void TextFormats_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
ProcessTextFormat();
}
private static void OnCurrentModeChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
(obj as EditorBox).OnCurrentModeChanged((Mode)e.OldValue, (Mode)e.NewValue);
}
/// <summary>
/// 从编辑模式切换到视图模式,进行文本格式计算
/// </summary>
/// <param name="oldMode"></param>
/// <param name="newMode"></param>
protected virtual void OnCurrentModeChanged(Mode oldMode, Mode newMode)
{
if (newMode == Mode.View)
{
ProcessTextFormat();
}
}
#endregion
#endregion
public EditorBox()
{
this.DefaultStyleKey = typeof(EditorBox);
TextFormats = new TextFormatCollection();
//通过附加属性增加鼠标双击事件
this.SetValue(MouseEventHelper.MouseDoubleClickProperty, new MouseButtonEventHandler(MouseDoubleClick));
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
AttachToVisualTree();
}
/// <summary>
/// 获取模板中的子控件,并附加处理
/// </summary>
void AttachToVisualTree()
{
//获取模板中的子控件
_editor = GetChildControl<TextBox>(PART_Editor);
_viewer = GetChildControl<TextBlock>(PART_View);
if (_editor != null)
{
//由于Silverlight的TextChanged事件只在Load之后才会触发,所以需要在Load之后初始化文本格式
_editor.Loaded += new RoutedEventHandler(InitTextFormat);
//按下回车回到视图模式
_editor.KeyDown += new KeyEventHandler(EnterViewMode);
//设置绑定关系
_editor.Text = this.Text;
this.SetBinding(TextProperty, new Binding("Text") { Source = _editor, Mode = BindingMode.TwoWay });
}
ProcessTextFormat();
}
/// <summary>
/// 第一次加载时,初始化文本格式
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void InitTextFormat(object sender, RoutedEventArgs e)
{
ProcessTextFormat();
}
/// <summary>
/// 进入视图模式
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void EnterViewMode(object sender, KeyEventArgs e)
{
//按回车进入查看状态
if (e.Key == Key.Enter)
{
VisualStateManager.GoToState(this, VisualState_View, false);
CurrentMode = Mode.View;
}
}
/// <summary>
/// 双击进入编辑模式(如果允许编辑)
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
//更换VisualStatus 双击进入编辑状态
if (CanEdit)
{
VisualStateManager.GoToState(this, VisualState_Edit, false);
CurrentMode = Mode.Edit;
}
}
/// <summary>
/// 处理文本格式
/// </summary>
void ProcessTextFormat()
{
if (_viewer != null && CurrentMode == Mode.View && this.TextFormats != null)
{
_viewer.Inlines.Clear();
//先按照StartIndex排序
var formats = this.TextFormats.OrderBy((format) => { return format.StartIndex; }).ToList();
int startIndex = 0;
int length = 0;
for (int i = 0; i < formats.Count; i++)
{
if (startIndex >= this.Text.Length)
break;
TextFormat format = formats[i];
Run run = new Run();
//重叠部分
if (format.StartIndex < startIndex)
{
throw new Exception("StartIndex不能重叠");
}
//不要求格式部分
else if (format.StartIndex > startIndex)
{
length = Math.Min(format.StartIndex - startIndex, this.Text.Length - startIndex);
run.Text = this.Text.Substring(startIndex, length);
startIndex += length;
i--;
}
//要求格式部分
else if (format.StartIndex == startIndex)
{
length = Math.Min(format.Length, this.Text.Length - startIndex);
run.Text = this.Text.Substring(startIndex, length);
if (format.FontFamily != null)
run.FontFamily = format.FontFamily;
run.FontSize = format.FontSize;
run.Foreground = format.Foreground;
startIndex += length;
}
_viewer.Inlines.Add(run);
}
//处理尾部的剩余部分
if (startIndex < this.Text.Length)
{
Run run = new Run();
length = this.Text.Length - startIndex;
run.Text = this.Text.Substring(startIndex, length);
_viewer.Inlines.Add(run);
}
}
}
/// <summary>
/// 获取指定名字的控件,并转换为对应类型
/// </summary>
/// <typeparam name="T">控件类型</typeparam>
/// <param name="ctrlName">控件名</param>
/// <returns>转换后的控件</returns>
protected T GetChildControl<T>(string ctrlName) where T : class
{
T ctrl = GetTemplateChild(ctrlName) as T;
return ctrl;
}
}