यहां सभी उत्तर केवल TextBox
पाठ चयन का उपयोग करने या मैन्युअल रूप से लागू करने की कोशिश कर रहे हैं, जो खराब प्रदर्शन या गैर-देशी व्यवहार (में लापरवाही बरतने) की ओर जाता हैTextBox
, मैनुअल कार्यान्वयन आदि में कोई कीबोर्ड समर्थन नहीं) की ओर जाता है।
चारों ओर खुदाई और WPF स्रोत कोड को पढ़ने के घंटों के बाद , मैंने इसके बजाय 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);
}
}
मैंने एक 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;