Semua jawaban di sini hanya menggunakan TextBox
atau mencoba menerapkan pemilihan teks secara manual, yang mengarah pada kinerja yang buruk atau perilaku non-pribumi (tanda sisipan berkedip TextBox
, tidak ada dukungan keyboard dalam implementasi manual, dll.)
Setelah berjam-jam menggali dan membaca kode sumber WPF , saya malah menemukan cara mengaktifkan pemilihan teks WPF asli untuk TextBlock
kontrol (atau benar-benar kontrol lain). Sebagian besar fungsi di sekitar pemilihan teks diimplementasikan dalam System.Windows.Documents.TextEditor
kelas sistem.
Untuk mengaktifkan pemilihan teks untuk kontrol Anda, Anda perlu melakukan dua hal:
Panggil TextEditor.RegisterCommandHandlers()
sekali untuk mendaftarkan penangan acara kelas
Buat instance TextEditor
untuk setiap instance dari kelas Anda dan berikan instance Anda System.Windows.Documents.ITextContainer
untuknya
Ada juga persyaratan yang mengatur Focusable
properti kontrol Anda True
.
Ini dia! Kedengarannya mudah, tetapi sayangnya TextEditor
kelas ditandai sebagai internal. Jadi saya harus menulis pembungkus refleksi di sekitarnya:
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);
}
}
Saya juga membuat SelectableTextBlock
turunan dari TextBlock
yang mengambil langkah-langkah yang disebutkan di atas:
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);
}
}
Pilihan lain adalah membuat properti terlampir untuk TextBlock
memungkinkan pemilihan teks sesuai permintaan. Dalam hal ini, untuk menonaktifkan seleksi lagi, kita perlu melepaskan a TextEditor
dengan menggunakan refleksi setara dari kode ini:
_editor.TextContainer.TextView = null;
_editor.OnDetach();
_editor = null;