यहां सभी उत्तर केवल 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;