ここでのすべての回答はTextBox
、テキスト選択を手動で使用するか実装しようとしているため、パフォーマンスが低下したり、ネイティブでTextBox
はない動作になります(でキャレットが点滅、手動実装ではキーボードがサポートされていないなど)。
WPFソースコードを何時間も調べて読んだ後、代わりに、TextBlock
コントロール(または実際には他のすべてのコントロール)のネイティブWPFテキスト選択を有効にする方法を発見しました。テキスト選択に関する機能のほとんどは、System.Windows.Documents.TextEditor
システムクラスに実装されています。
コントロールのテキスト選択を有効にするには、2つのことを行う必要があります。
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);
}
}
上記の手順を実行SelectableTextBlock
するからも派生を作成しましたTextBlock
。
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;