所有的答案,這裏只是用TextBox
或試圖手動實現文本選擇,從而導致性能不佳或者非本地的行爲(在TextBox
閃爍插入符號,沒有鍵盤支持手動實現等)
經過幾個小時的挖掘並閱讀WPF source code,我反而找到了一種爲TextBlock
控件(或其他任何控件)啓用本機WPF文本選擇的方法。圍繞文本選擇的大多數功能都在System.Windows.Documents.TextEditor
系統類中實現。
要啓用文本選擇對你的控制,你需要做兩件事情:
呼叫TextEditor.RegisterCommandHandlers()
一次註冊類 事件處理
爲你的類的每個實例創建的TextEditor
實例並將System.Windows.Documents.ITextContainer
的底層實例傳遞給它
還有一個要求,您的控件的Focusable
屬性設置爲True
。
這就是它!聽起來很容易,但不幸的是,TextEditor
類被標記爲內部。所以,我不得不寫它周圍的反射包裝:
class TextEditorWrapper
{
private static readonly Type TextEditorType = Type.GetType("System.Windows.Documents.TextEditor, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
private static readonly PropertyInfo IsReadOnlyProp = TextEditorType.GetProperty("IsReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
private static readonly PropertyInfo TextViewProp = TextEditorType.GetProperty("TextView", BindingFlags.Instance | BindingFlags.NonPublic);
private static readonly MethodInfo RegisterMethod = TextEditorType.GetMethod("RegisterCommandHandlers",
BindingFlags.Static | BindingFlags.NonPublic, null, new[] { typeof(Type), typeof(bool), typeof(bool), typeof(bool) }, null);
private static readonly Type TextContainerType = Type.GetType("System.Windows.Documents.ITextContainer, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
private static readonly PropertyInfo TextContainerTextViewProp = TextContainerType.GetProperty("TextView");
private static readonly PropertyInfo TextContainerProp = typeof(TextBlock).GetProperty("TextContainer", BindingFlags.Instance | BindingFlags.NonPublic);
public static void RegisterCommandHandlers(Type controlType, bool acceptsRichContent, bool readOnly, bool registerEventListeners)
{
RegisterMethod.Invoke(null, new object[] { controlType, acceptsRichContent, readOnly, registerEventListeners });
}
public static TextEditorWrapper CreateFor(TextBlock tb)
{
var textContainer = TextContainerProp.GetValue(tb);
var editor = new TextEditorWrapper(textContainer, tb, false);
IsReadOnlyProp.SetValue(editor._editor, true);
TextViewProp.SetValue(editor._editor, TextContainerTextViewProp.GetValue(textContainer));
return editor;
}
private readonly object _editor;
public TextEditorWrapper(object textContainer, FrameworkElement uiScope, bool isUndoEnabled)
{
_editor = Activator.CreateInstance(TextEditorType, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.CreateInstance,
null, new[] { textContainer, uiScope, isUndoEnabled }, null);
}
}
我還創建從TextBlock
獲得的SelectableTextBlock
這需要上面提到的步驟:
public class SelectableTextBlock : TextBlock
{
static SelectableTextBlock()
{
FocusableProperty.OverrideMetadata(typeof(SelectableTextBlock), new FrameworkPropertyMetadata(true));
TextEditorWrapper.RegisterCommandHandlers(typeof(SelectableTextBlock), true, true, true);
// remove the focus rectangle around the control
FocusVisualStyleProperty.OverrideMetadata(typeof(SelectableTextBlock), new FrameworkPropertyMetadata((object)null));
}
private readonly TextEditorWrapper _editor;
public SelectableTextBlock()
{
_editor = TextEditorWrapper.CreateFor(this);
}
}
另一種選擇是創建一個連接財產TextBlock
啓用文本選擇按需。在這種情況下,再次禁用選擇,需要通過使用反射相當於該代碼的分離一個TextEditor
:
_editor.TextContainer.TextView = null;
_editor.OnDetach();
_editor = null;
我會嘗試使用RichTextBox控件,看看是否會工作。但從之前的經驗來看,使用richtextbox更爲重要。 – 2008-09-25 22:06:58
您是否想過使用FlowDocumentScrollViewer,並在FlowDocument中包含段落和運行? - 當我需要可選文本時,這對我非常有用,並且每個段落和運行可以單獨設置樣式。 – BrainSlugs83 2015-01-25 04:58:06
已經嘗試了下面的一些解決方法,FlowDocumentScrollViewer是前進的方向。它似乎佔據了RichTextBox和TextBlock之間的有用中間地帶。 – 2016-05-19 15:04:47