Gibt es eine Möglichkeit, einen WPF-Textblock auswählbar zu machen?


224

Ich möchte den Text in Witty , einem Open-Source-Twitter-Client, auswählbar machen. Es wird derzeit mit einem benutzerdefinierten Textblock angezeigt. Ich muss einen TextBlock verwenden, da ich mit den Inlines des Textblocks arbeite, um den @Benutzernamen und die Links als Hyperlinks anzuzeigen und zu formatieren. Eine häufige Anforderung besteht darin, den Text kopieren und einfügen zu können. Dazu muss ich den TextBlock auswählbar machen.

Ich habe versucht, es zum Laufen zu bringen, indem ich den Text mit einer schreibgeschützten TextBox angezeigt habe, die so gestaltet ist, dass sie wie ein Textblock aussieht. In meinem Fall funktioniert dies jedoch nicht, da eine TextBox keine Inlines enthält. Mit anderen Worten, ich kann den Text in einer TextBox nicht wie bei einem TextBlock einzeln formatieren oder formatieren.

Irgendwelche Ideen?


1
Ich werde versuchen, das RichTextBox-Steuerelement zu verwenden, um festzustellen, ob dies funktioniert. Aus früheren Erfahrungen ist die Arbeit mit der Richtextbox jedoch viel komplizierter.
Alan Le

Haben Sie darüber nachgedacht, einen FlowDocumentScrollViewer mit einem FlowDocument zu verwenden, das Absätze und Läufe enthält? - Dies funktioniert ziemlich gut für mich, wenn ich auswählbaren Text benötige und jeder Absatz und jede Ausführung separat gestaltet werden kann.
BrainSlugs83

Nachdem FlowDocumentScrollViewer einige der folgenden Problemumgehungen ausprobiert hatte, war er der richtige Weg. Es scheint einen nützlichen Mittelweg zwischen RichTextBox und TextBlock einzunehmen.
Tom Makin

Abstimmung für die Annahme einer Antwort, die nicht Ihren Anforderungen entspricht.
Blechdose

Antworten:


218
<TextBox Background="Transparent"
         BorderThickness="0"
         Text="{Binding Text, Mode=OneWay}"
         IsReadOnly="True"
         TextWrapping="Wrap" />

6
Ich habe ein Projekt, das viele TextBlocks / Labels enthält. Ich kann sie nicht wirklich in TextBoxen umwandeln. Was ich tun möchte, ist, der Ressource auf App-Ebene einen magischen Stil hinzuzufügen, der auf alle angewendet werden soll, damit er sich auf alle Beschriftungen / Textblöcke auswirkt, und ihren internen Textpräsentator als schreibgeschützte Textbox zu erstellen es zu tun?
Shimmy Weitzhandler

5
Sie können IsTabStop = "False" abhängig von Ihrer Situation hinzufügen
Karsten

1
+1 Sehr schöne Lösung! Ich habe ein Padding = "0" hinzugefügt, da in meinem Projekt der untere Teil des Textes abgeschnitten wurde ... Vielleicht wegen eines Stils woanders.
reSPAWNed

123
-1 In der Frage wird speziell gefragt, wie ein Textblock auswählbar gemacht werden kann. Weil er die Eigenschaft "Inlines" (die textBoxes nicht haben) nicht verlieren möchte. Diese 'Antwort' schlägt nur vor, ein Textfeld wie einen Textblock aussehen zu lassen.
14.

19
@AlanLe Warum hast du diese Antwort akzeptiert, als du ausdrücklich gesagt hast, dass du sie nicht willst? Und warum haben 147 ahnungslose Menschen dafür gestimmt?
Jim Balter

66

Alle Antworten hier verwenden lediglich eine TextBoxoder versuchen, die Textauswahl manuell zu implementieren, was zu einer schlechten Leistung oder einem nicht nativen Verhalten führt (blinkendes Caret in)TextBox , keine Tastaturunterstützung bei manuellen Implementierungen usw.).

Nachdem ich mich stundenlang umgesehen und den WPF-Quellcode gelesen hatte , entdeckte ich stattdessen eine Möglichkeit, die native WPF-Textauswahl für TextBlockSteuerelemente (oder wirklich alle anderen Steuerelemente) zu aktivieren . Die meisten Funktionen zur Textauswahl sind in der Systemklasse implementiert System.Windows.Documents.TextEditor.

Um die Textauswahl für Ihr Steuerelement zu aktivieren, müssen Sie zwei Dinge tun:

  1. Rufen Sie TextEditor.RegisterCommandHandlers()einmal an, um Klassenereignishandler zu registrieren

  2. Erstellen Sie eine Instanz von TextEditorfür jede Instanz Ihrer Klasse und übergeben Sie die zugrunde liegende Instanz Ihrer Klasse System.Windows.Documents.ITextContaineran diese

Es gibt auch eine Anforderung, auf die die FocusableEigenschaft Ihres Steuerelements festgelegt ist True.

Das ist es! Klingt einfach, aber leider TextEditorist die Klasse als intern markiert. Also musste ich einen Reflection Wrapper darum schreiben:

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);
    }
}

Ich habe auch eine SelectableTextBlockAbleitung erstellt TextBlock, die die oben genannten Schritte ausführt:

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);
    }
}

Eine andere Möglichkeit wäre, eine angehängte Eigenschaft zu erstellen TextBlock, um die Textauswahl bei Bedarf zu ermöglichen. In diesem Fall muss zum Löschen der Auswahl a TextEditorunter Verwendung des Reflexionsäquivalents dieses Codes getrennt werden:

_editor.TextContainer.TextView = null;
_editor.OnDetach();
_editor = null;

1
Wie würden Sie die SelectableTextBlock-Klasse in einer anderen xaml verwenden, die sie enthalten sollte?
Yoav Feuerstein

1
Auf die gleiche Weise würden Sie jedes andere benutzerdefinierte Steuerelement verwenden. siehe stackoverflow.com/a/3768178/332528 zum Beispiel
Torvin

3
@BillyWilloughby Ihre Lösung emuliert nur die Auswahl. Es fehlen viele native Auswahlfunktionen: Tastaturunterstützung, Kontextmenü usw. Meine Lösung
aktiviert

3
Es scheint, dass diese Lösung funktioniert , wenn das s TextBlockeingebettet hat, Hyperlinksolange das Hyperlinknicht die letzte Inline darin ist. Durch Hinzufügen eines nachgestellten Leerzeichens Runzum Inhalt wird das zugrunde liegende Problem behoben , das zum Auslösen führt ExecutionEngineException.
Anton Tykhyy

2
Das ist toll! Außer , wenn Sie TextTrimming="CharacterEllipsis"auf dem TextBlockund die zur Verfügung stehende Breite reicht nicht aus , wenn Sie den Mauszeiger über die bewegen ... es mit System.ArgumentException abstürzt „Gewünscht Abstand außerhalb des Inhalts des zugehörigen Dokuments.“ at System.Windows.Documents.TextPointer.InitializeOffset (TextPointer-Position, Int32-Abstand, LogicalDirection-Richtung) :( Ich weiß nicht, ob es eine andere Problemumgehung gibt, als TextTrimming auf None zu setzen.
Dave Huang

32

Ich konnte kein Beispiel finden, um die Frage wirklich zu beantworten. Alle Antworten verwendeten eine Textbox oder RichTextbox. Ich brauchte eine Lösung, mit der ich einen TextBlock verwenden konnte, und diese Lösung habe ich erstellt.

Ich glaube, der richtige Weg, dies zu tun, besteht darin, die TextBlock-Klasse zu erweitern. Dies ist der Code, mit dem ich die TextBlock-Klasse erweitert habe, damit ich den Text auswählen und in die Zwischenablage kopieren kann. "sdo" ist die Namespace-Referenz, die ich in der WPF verwendet habe.

WPF mit erweiterter Klasse:

xmlns:sdo="clr-namespace:iFaceCaseMain"

<sdo:TextBlockMoo x:Name="txtResults" Background="Black" Margin="5,5,5,5" 
      Foreground="GreenYellow" FontSize="14" FontFamily="Courier New"></TextBlockMoo>

Code Behind für Extended Class:

public partial class TextBlockMoo : TextBlock 
{
    TextPointer StartSelectPosition;
    TextPointer EndSelectPosition;
    public String SelectedText = "";

    public delegate void TextSelectedHandler(string SelectedText);
    public event TextSelectedHandler TextSelected;

    protected override void OnMouseDown(MouseButtonEventArgs e)
    {
        base.OnMouseDown(e);
        Point mouseDownPoint = e.GetPosition(this);
        StartSelectPosition = this.GetPositionFromPoint(mouseDownPoint, true);            
    }

    protected override void OnMouseUp(MouseButtonEventArgs e)
    {
        base.OnMouseUp(e);
        Point mouseUpPoint = e.GetPosition(this);
        EndSelectPosition = this.GetPositionFromPoint(mouseUpPoint, true);

        TextRange otr = new TextRange(this.ContentStart, this.ContentEnd);
        otr.ApplyPropertyValue(TextElement.ForegroundProperty, new SolidColorBrush(Colors.GreenYellow));

        TextRange ntr = new TextRange(StartSelectPosition, EndSelectPosition);
        ntr.ApplyPropertyValue(TextElement.ForegroundProperty, new SolidColorBrush(Colors.White));

        SelectedText = ntr.Text;
        if (!(TextSelected == null))
        {
            TextSelected(SelectedText);
        }
    }
}

Beispielfenstercode:

    public ucExample(IInstanceHost host, ref String WindowTitle, String ApplicationID, String Parameters)
    {
        InitializeComponent();
        /*Used to add selected text to clipboard*/
        this.txtResults.TextSelected += txtResults_TextSelected;
    }

    void txtResults_TextSelected(string SelectedText)
    {
        Clipboard.SetText(SelectedText);
    }

1
Dies sollte die akzeptierte Antwort sein! Keine Reflection-Hacks, keine TextBox ... Und es kann leicht in ein wiederverwendbares Verhalten umgewandelt werden. Sehr schön danke!
Thomas Levesque

19

Wenden Sie diesen Stil auf Ihre TextBox an und fertig (inspiriert von diesem Artikel ):

<Style x:Key="SelectableTextBlockLikeStyle" TargetType="TextBox" BasedOn="{StaticResource {x:Type TextBox}}">
    <Setter Property="IsReadOnly" Value="True"/>
    <Setter Property="IsTabStop" Value="False"/>
    <Setter Property="BorderThickness" Value="0"/>
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="Padding" Value="-2,0,0,0"/>
    <!-- The Padding -2,0,0,0 is required because the TextBox
        seems to have an inherent "Padding" of about 2 pixels.
        Without the Padding property,
        the text seems to be 2 pixels to the left
        compared to a TextBlock
    -->
    <Style.Triggers>
        <MultiTrigger>
            <MultiTrigger.Conditions>
                <Condition Property="IsMouseOver" Value="False" />
                <Condition Property="IsFocused" Value="False" />
            </MultiTrigger.Conditions>
            <Setter Property="Template">
                <Setter.Value>
                <ControlTemplate TargetType="{x:Type TextBox}">
                    <TextBlock Text="{TemplateBinding Text}" 
                             FontSize="{TemplateBinding FontSize}"
                             FontStyle="{TemplateBinding FontStyle}"
                             FontFamily="{TemplateBinding FontFamily}"
                             FontWeight="{TemplateBinding FontWeight}"
                             TextWrapping="{TemplateBinding TextWrapping}"
                             Foreground="{DynamicResource NormalText}"
                             Padding="0,0,0,0"
                                       />
                </ControlTemplate>
                </Setter.Value>
            </Setter>
        </MultiTrigger>
    </Style.Triggers>
</Style>


2
Ein weiterer Zusatz: Die Polsterung sollte -2,0, -2,0 betragen. In der TextBox wird ein TextBoxView-Steuerelement mit einem Standardrand von 2,0,2,0 erstellt. Leider können Sie den Stil nicht neu definieren, da er als intern markiert ist.
fdub

11
Niemand scheint lesen zu können. Das OP benötigt einen TextBlock, keine TextBox, die wie ein TextBlock gestaltet ist.
Jim Balter

18

Erstellen Sie ControlTemplate für den TextBlock und fügen Sie eine TextBox mit schreibgeschütztem Eigenschaftssatz ein. Oder verwenden Sie einfach TextBox und machen Sie es schreibgeschützt. Dann können Sie die TextBox.Style so ändern, dass sie wie TextBlock aussieht.


11
Wie legen Sie die ControlTemplate für einen TextBlock fest? Ich kann die Immobilie nicht finden?
HaxElit

18
Dieser Ansatz funktioniert nicht, wenn Ihr TextBlock Inline-Elemente enthält. Was ist, wenn Sie Hyperlinks oder Läufe mit fettem oder kursivem Text haben? TextBox unterstützt diese nicht.
Dthrasher

1
Funktioniert nicht, wenn Sie Inline-Läufe verwenden, und wie HaxElit gefragt hat, bin ich mir nicht sicher, was Sie unter Steuerungsvorlage verstehen.
Ritch Melton

7
-1 TextBlock verfügt nicht über eine ControlTemplate, da es sich um eine direkte Unterklasse von FrameworkElement handelt. TextBox hingegen ist eine Unterklasse von Control.
reSPAWNed

5
Warum kann niemand lesen? Das OP sagte ausdrücklich, dass ein TextBlock benötigt wird, kein TextBox, da TextBlock die Inline-Formatierung unterstützt und TextBox dies nicht tut. Warum bekommen völlig falsche Müllantworten wie diese zahlreiche positive Stimmen?
Jim Balter

10

Ich bin nicht sicher, ob Sie einen TextBlock auswählbar machen können, aber eine andere Option wäre die Verwendung einer RichTextBox - sie ähnelt einer von Ihnen vorgeschlagenen TextBox, unterstützt jedoch die gewünschte Formatierung.


1
Ich habe dies versucht und musste dabei die RichTextBox mit einer Abhängigkeitseigenschaft bindbar machen. Leider werden die alten Flussdokumente nicht richtig verworfen und der Speicher leckt wie verrückt. Alan, ich frage mich, ob du einen Weg gefunden hast, das zu umgehen?
John Noonan

@AlanLe Von allen Antworten hier ist dies nur eine von zwei, die tatsächlich die gestellte Frage beantworten ... alle anderen sprechen davon, eine TextBox so zu gestalten, dass sie wie ein TextBlock aussieht, ohne dass eine Formatierung erforderlich ist. Es ist bizarr und bedauerlich, dass das OP eine dieser Nichtantworten akzeptiert hat, anstatt die richtige Antwort, um RichTextBox anstelle von TextBox zu verwenden.
Jim Balter

9

Laut Windows Dev Center :

TextBlock.IsTextSelectionEnabled-Eigenschaft

[Aktualisiert für UWP-Apps unter Windows 10. Artikel zu Windows 8.x finden Sie im Archiv ]

Ruft einen Wert ab oder legt einen Wert fest, der angibt, ob die Textauswahl im TextBlock aktiviert ist , entweder durch Benutzeraktion oder durch Aufrufen einer auswahlbezogenen API.


5
Leider nicht kompatibel mit Win7 (manchmal ist es ein Muss)
Yury Schkatula

24
Amswer erscheint falsch. IsTextSelectionEnabled ist nur für UWP, nicht für WPF - die ursprüngliche Frage hat WPF angegeben.
Papageientaucher

6

Während die Frage "Auswählbar" lautet, glaube ich, dass das beabsichtigte Ergebnis darin besteht, den Text in die Zwischenablage zu bringen. Dies kann einfach und elegant erreicht werden, indem ein Kontextmenü und ein Menüelement namens "Kopieren" hinzugefügt werden, mit denen der Eigenschaftswert "Textblock-Text" in die Zwischenablage verschoben wird. Nur eine Idee.


4

TextBlock hat keine Vorlage. Um dies zu erreichen, müssen wir eine TextBox verwenden, deren Stil geändert wird, um sich als TextBlock zu verhalten.

<Style x:Key="TextBlockUsingTextBoxStyle" BasedOn="{x:Null}" TargetType="{x:Type TextBox}">
    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="BorderBrush" Value="{StaticResource TextBoxBorder}"/>
    <Setter Property="BorderThickness" Value="0"/>
    <Setter Property="Padding" Value="1"/>
    <Setter Property="AllowDrop" Value="true"/>
    <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
    <Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
    <Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TextBox}">
                <TextBox BorderThickness="{TemplateBinding BorderThickness}" IsReadOnly="True" Text="{TemplateBinding Text}" Background="{x:Null}" BorderBrush="{x:Null}" />
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Welche Vorteile bietet dieser Ansatz gegenüber anderen Antworten? Ich sehe keine.
Surfen

Ich habe diesen Stil ausprobiert: TextBoxBorder ist nicht definiert. Wenn Sie es
auskommentieren

Dieser Beispielcode ist ausgezeichnet und zeigt, wie Sie die Standardfarbe für einen TextBlock erhalten.
Contango

1
Das ist ziemlich verwirrt. Erstens ist der x: Key "TextBlockUsingTextBoxStyle" rückwärts; Es sollte "TextBoxUsingTextBlockStyle" sein. Zweitens wusste das OP bereits, wie man eine TextBox wie einen TextBlock formatiert, sagte jedoch wiederholt, dass er dies nicht verwenden könne, da er Inlines für die Formatierung benötige.
Jim Balter

2

Es gibt eine alternative Lösung, die möglicherweise an die in diesem Blogbeitrag beschriebene RichTextBox angepasst werden kann - sie hat einen Auslöser verwendet, um die Steuerelementvorlage auszutauschen, wenn die Verwendung über dem Steuerelement schwebt -, um die Leistung zu verbessern


1
Dein Link ist tot. Bitte fügen Sie alle relevanten Informationen in eine Antwort ein und verwenden Sie Links nur als Zitate.
Jim Balter

1

new TextBox
{
   Text = text,
   TextAlignment = TextAlignment.Center,
   TextWrapping = TextWrapping.Wrap,
   IsReadOnly = true,
   Background = Brushes.Transparent,
   BorderThickness = new Thickness()
         {
             Top = 0,
             Bottom = 0,
             Left = 0,
             Right = 0
         }
};


1
Das ist nicht hilfreich. Lesen Sie die Frage, um zu sehen, was das OP eigentlich wollte.
Jim Balter

1

Das Hinzufügen zu @ torvins Antwort und wie @ Dave Huang in den Kommentaren erwähnt, wenn Sie TextTrimming="CharacterEllipsis"die Anwendung aktiviert haben, stürzt ab, wenn Sie mit der Maus über die Auslassungspunkte fahren.

Ich habe andere im Thread erwähnte Optionen zur Verwendung einer TextBox ausprobiert, aber es scheint auch nicht die Lösung zu sein, da es nicht die Auslassungspunkte anzeigt und auch, wenn der Text zu lang ist, um in den Container zu passen, in dem der Inhalt ausgewählt wird Das Textfeld "scrollt" intern, was kein TextBlock-Verhalten ist.

Ich denke, die beste Lösung ist @ torvins Antwort, hat aber den bösen Absturz, wenn man über der Ellipse schwebt.

Ich weiß, dass es nicht schön ist, aber das interne Abonnieren / Abbestellen nicht behandelter Ausnahmen und das Behandeln der Ausnahme war die einzige Möglichkeit, dieses Problem zu lösen. Bitte teilen Sie mir mit, ob jemand eine bessere Lösung hat :)

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);

        this.Loaded += (sender, args) => {
            this.Dispatcher.UnhandledException -= Dispatcher_UnhandledException;
            this.Dispatcher.UnhandledException += Dispatcher_UnhandledException;
        };
        this.Unloaded += (sender, args) => {
            this.Dispatcher.UnhandledException -= Dispatcher_UnhandledException;
        };
    }

    private void Dispatcher_UnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
    {
        if (!string.IsNullOrEmpty(e?.Exception?.StackTrace))
        {
            if (e.Exception.StackTrace.Contains("System.Windows.Controls.TextBlock.GetTextPositionFromDistance"))
            {
                e.Handled = true;
            }
        }
    }
}

0

Ich habe SelectableTextBlock in meiner OpenSource-Steuerelementbibliothek implementiert . Sie können es so verwenden:

<jc:SelectableTextBlock Text="Some text" />

4
Dies verwendet nur eine TextBox, wie so viele andere Antworten aus vielen Jahren zuvor.
Chris

0
public MainPage()
{
    this.InitializeComponent();
    ...
    ...
    ...
    //Make Start result text copiable
    TextBlockStatusStart.IsTextSelectionEnabled = true;
}

-1
Really nice and easy solution, exactly what I wanted !

Ich bringe einige kleine Modifikationen mit

public class TextBlockMoo : TextBlock 
{
    public String SelectedText = "";

    public delegate void TextSelectedHandler(string SelectedText);
    public event TextSelectedHandler OnTextSelected;
    protected void RaiseEvent()
    {
        if (OnTextSelected != null){OnTextSelected(SelectedText);}
    }

    TextPointer StartSelectPosition;
    TextPointer EndSelectPosition;
    Brush _saveForeGroundBrush;
    Brush _saveBackGroundBrush;

    TextRange _ntr = null;

    protected override void OnMouseDown(MouseButtonEventArgs e)
    {
        base.OnMouseDown(e);

        if (_ntr!=null) {
            _ntr.ApplyPropertyValue(TextElement.ForegroundProperty, _saveForeGroundBrush);
            _ntr.ApplyPropertyValue(TextElement.BackgroundProperty, _saveBackGroundBrush);
        }

        Point mouseDownPoint = e.GetPosition(this);
        StartSelectPosition = this.GetPositionFromPoint(mouseDownPoint, true);            
    }

    protected override void OnMouseUp(MouseButtonEventArgs e)
    {
        base.OnMouseUp(e);
        Point mouseUpPoint = e.GetPosition(this);
        EndSelectPosition = this.GetPositionFromPoint(mouseUpPoint, true);

        _ntr = new TextRange(StartSelectPosition, EndSelectPosition);

        // keep saved
        _saveForeGroundBrush = (Brush)_ntr.GetPropertyValue(TextElement.ForegroundProperty);
        _saveBackGroundBrush = (Brush)_ntr.GetPropertyValue(TextElement.BackgroundProperty);
        // change style
        _ntr.ApplyPropertyValue(TextElement.BackgroundProperty, new SolidColorBrush(Colors.Yellow));
        _ntr.ApplyPropertyValue(TextElement.ForegroundProperty, new SolidColorBrush(Colors.DarkBlue));

        SelectedText = _ntr.Text;
    }
}

1
Sie müssen bitte erklären, was Sie gegenüber der Antwort unten geändert haben. -1
Alex Hope O'Connor

Zeile 51 lautet: System.ArgumentNullException: 'Wert darf nicht null sein. Parametername: Position1 '
rollt
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.