Ich versuche, die TextPointer-Klasse in einer WPF RichTextBox zu verstehen.
Ich möchte in der Lage sein, sie im Auge zu behalten, damit ich Informationen mit Bereichen im Text verknüpfen kann.
Ich arbeite derzeit an einem sehr einfachen Beispiel, um herauszufinden, was vor sich geht. Im PreviewKeyDown-Event speichere ich die Caret-Position und dann im PreviewKeyUp-Event einen TextRange basierend auf den Vor- und Nach-Caret-Positionen. Hier ist ein Codebeispiel, das veranschaulicht, was ich versuche zu tun:
%Vor%Das Problem ist, dass der Text, den ich bekomme, leer ist. Wenn ich zum Beispiel das Zeichen 'a' eintippe, würde ich erwarten, den Text "a" im TextRange zu finden.
Weiß jemand, was schief läuft? Es könnte etwas sehr einfaches sein, aber ich habe einen Nachmittag damit verbracht, nirgendwohin zu kommen.
Ich versuche, die neue WPF-Technologie zu nutzen, finde aber, dass insbesondere die RichTextBox so kompliziert ist, dass selbst solche einfachen Dinge schwierig werden. Wenn jemand irgendwelche Links hat, die den TextPointer gut erklären, würde ich mich freuen, wenn Sie es mich wissen lassen können.
Wenn Sie Text aus einem FlowDocument hinzufügen und entfernen, passen alle TextPointer ihre Position basierend auf einer Anzahl von Heuristiken an, die dafür sorgen, dass sie so nahe wie möglich am "Ort" bleiben.
Das Löschen ist einfach: Wenn sich der TextPointer im gelöschten Text befindet, endet er zwischen den Zeichen, die den gelöschten Text umgeben haben. Aber für Einfügungen ist es nicht so einfach: Wenn Text oder andere Elemente genau in einen bestehenden TextPointer in ein FlowDocument eingefügt werden, sollte der TextPointer vor oder nach dem eingefügten Text enden? TextPointer hat eine Eigenschaft namens "LogicalDirection", die dies steuert.
Was in Ihrem Fall passiert, ist, dass die Position "caretBefore", die Sie erfassen, genau die Textposition ist, in der das eingegebene Zeichen eingefügt wird, und in Ihren Testfällen ist Ihre logische Richtung LogicalDirection.Forward. Wenn also das Zeichen eingefügt wird, endet Ihr "cavetBefore" nach das eingefügte Zeichen, das mit TextPosition übereinstimmt und Ihnen einen leeren TextRange gibt.
Wie bekommt ein TextPointer eine LogicalDirection zugewiesen? Wenn Sie auf die RichTextBox klicken, um die Caret-Position festzulegen, wird der Klick als zwischen zwei Zeichen interpretiert interpretiert. Wenn der tatsächliche Punkt, auf den Sie geklickt haben, auf dem zweiten Zeichen lag, ist LogicalDirection auf Forward festgelegt, aber wenn der tatsächliche Punkt, auf den Sie geklickt haben, das erste Zeichen war, wird LogicalDirection auf Rückwärts festgelegt.
Versuchen Sie dieses Experiment:
Dieses Verhalten ist kontraintuitiv: Wenn Sie nicht wissen, dass LogicalDirection existiert, würden Sie denken, dass ein Klick auf die rechte Seite von B oder die linke Seite von C Ihnen genau die gleiche Caret-Position geben würde.
Hinweis: Eine einfache Möglichkeit, um zu visualisieren, was vor sich geht, ist, dass Sie Ihre MessageBox.Show befehlen und stattdessen %code%
eingebenWie erreichen Sie das gewünschte Ergebnis? LogicalDirection ist schreibgeschützt. Eine Möglichkeit besteht darin, TextRange zu verwenden, um den Aufbau eines TextPointer mit einer logischen Rückwärtsrichtung zu erzwingen:
%Vor%Machen Sie das in PreviewKeyDown. Wenn Sie bis PreviewKeyUp warten, ist es schon zu spät: caretBefore ist umgezogen. Das funktioniert, denn soweit ich das beurteilen kann, hat der Start einer nicht leeren TextRange immer eine logische Rückwärtsrichtung.
Eine andere Option ist das Speichern des Symboloffsets vom Anfang des Dokuments (beachten Sie, dass dies kein Zeichenoffset ist!). In diesem Fall könnten Sie den Offset in PreviewKeyDown speichern:
%Vor%und setzen Sie caretBefore auf den gleichen Symbol-Offset in PreviewKeyUp zurück:
%Vor%Obwohl dies funktioniert, ist es nicht so allgemein wie den TextPointer zu zwingen, eine Rückwärts-LogicalDirection zu haben: Alle Textänderungen früher im Dokument zwischen PreviewKeyDown und PreviewKeyUp verursachen, dass die Symbol-Offset-Berechnung den falschen Ort findet, was TextPointers ist wurden entwickelt, um in erster Linie zu beheben.
Ich kenne keine guten Quellen, um etwas über TextPointer zu lernen, außer das Lesen der Dokumentation und das Spielen mit ihnen, was genau das ist, was Sie bereits getan haben.