WPF Richtextbox eigene Formatierungen definieren

  • WPF

Es gibt 40 Antworten in diesem Thema. Der letzte Beitrag () ist von Translating-IT.

    über den Code behind Text mit Wellenlinien unterstreichen. ;)
    :!: Leider hab ich nicht immer Zeit zum Programmieren, da es eher ein Hobby ist. Falls ich mal im Forum ne Frage stelle und länger nicht antworte, nicht böse sein: Ich bin dann entweder beruflich oder mit der Familie zu sehr eingespannt oder einfach zu müde. Das kann erfahrungsgemäß auch mal über Wochen dauern, aber ich melde mich immer und setze die Frage ggf. auf beantwortet.

    Translating-IT schrieb:

    über den Code behind Text mit Wellenlinien unterstreichen. ;)

    Ich bin so froh, dass du mich aufklärst :D

    Das - in der Tat - war mir schon klar. Aber ich frage mich, wie dein Gedanke war, das anzustellen? Denn wenn ich den Code richtig lese, dann unterstreichst du eine absolute Stelle?

    PadreSperanza schrieb:


    Ich bin so froh, dass du mich aufklärst :D


    Immer wieder gerne. ;)

    ich hab ja nicht gesagt, dass ich das absolut durchdacht habe. O:) Wäre mir wahrscheinlich dann aufgefallen, wenn ich herausgefunden habe, wie ich es überhaupt in der RTB auf Text anwende … Ich hatte es so verstanden, dass dies nur die Definition (aufgrund der expliziten Punkte) ist, die dann auf den Text (die Auswahl) angewendet, das Ergebnis unter der Auswahl liefert und automatisch angepasst wird. Woran erkennst Du, dass es auf eine absolute Stelle geht?

    So, ich mach mich für heute mal ins Bettchen.
    :!: Leider hab ich nicht immer Zeit zum Programmieren, da es eher ein Hobby ist. Falls ich mal im Forum ne Frage stelle und länger nicht antworte, nicht böse sein: Ich bin dann entweder beruflich oder mit der Familie zu sehr eingespannt oder einfach zu müde. Das kann erfahrungsgemäß auch mal über Wochen dauern, aber ich melde mich immer und setze die Frage ggf. auf beantwortet.
    Wie kann ich den Code für die Wellenlinie eigentlich in eine TextDecorationCollection packen?
    :!: Leider hab ich nicht immer Zeit zum Programmieren, da es eher ein Hobby ist. Falls ich mal im Forum ne Frage stelle und länger nicht antworte, nicht böse sein: Ich bin dann entweder beruflich oder mit der Familie zu sehr eingespannt oder einfach zu müde. Das kann erfahrungsgemäß auch mal über Wochen dauern, aber ich melde mich immer und setze die Frage ggf. auf beantwortet.
    grml... Du warst 9 Minuten zu früh dran. Also wirklich …

    da fehlte noch was:

    VB.NET-Quellcode

    1. Dim squiggly As TextDecoration = New TextDecoration()
    2. squiggly.Pen = New Pen(squiggly_brush, 6)


    Aber ich kann die aus irgendeinem Grund nicht für die RTB abrufen.

    EDIT: bei einer Textbox dürfte es so implementiert werden:

    VB.NET-Quellcode

    1. textbox.TextDecorations.Add(squiggly)


    aber für RTB habe ich bis jetzt kein Add für TextDecorations gefunden.

    :!: Leider hab ich nicht immer Zeit zum Programmieren, da es eher ein Hobby ist. Falls ich mal im Forum ne Frage stelle und länger nicht antworte, nicht böse sein: Ich bin dann entweder beruflich oder mit der Familie zu sehr eingespannt oder einfach zu müde. Das kann erfahrungsgemäß auch mal über Wochen dauern, aber ich melde mich immer und setze die Frage ggf. auf beantwortet.
    na ja, um eine TextDecoration nutzen zu können, musst du sie in eine TextDecorationCollection schmeißen:

    VB.NET-Quellcode

    1. Dim SQCollection as TextDecorationCollection = new TextDecorationCollection
    2. SQCollection.Add(squiggly)


    und dann kannst du diese Collection deinen Runs mit auf den Weg geben.
    ach geh, Du willst mich nur ärgern … warst schon wieder zu schnell ^^

    bin total auf der Leitung gesessen. War wohl schon so auf andere Lösungen eingeschossen, dass ich das Offensichtliche nicht mehr gesehen habe. Mit Deinem Code von gestern hast Du mir ja schon geschrieben, wie ich was einer TextDecorationCollection hinzufüge. An sich fehlte mir nur der vorhin gepostete Code als Übergang dorthin. Habe das hier hinzugefügt und getestet: Es funktioniert!

    VB.NET-Quellcode

    1. Dim wavy As New TextDecorationCollection
    2. wavy.Add(squiggly)


    Edit:
    So, hier noch mit einer kleinen Anpassung, damit die Wellenlinie nicht direkt am Text klebt, dann der vollständige Code: (oder ist der noch optimierbar?)

    VB.NET-Quellcode

    1. Dim path_pen As Pen = New Pen(New SolidColorBrush(Colors.Red), 0.2)
    2. path_pen.EndLineCap = PenLineCap.Square
    3. path_pen.StartLineCap = PenLineCap.Square
    4. Dim path_start As Point = New Point(0, 1)
    5. Dim path_segment As BezierSegment = New BezierSegment(New Point(1, 0), New Point(2, 2), New Point(3, 1), True)
    6. Dim path_figure As PathFigure = New PathFigure(path_start, New PathSegment() {path_segment}, False)
    7. Dim path_geometry As PathGeometry = New PathGeometry(New PathFigure() {path_figure})
    8. Dim squiggly_brush As DrawingBrush = New DrawingBrush()
    9. squiggly_brush.Viewport = New Rect(0, 0, 7.8, 5.2) 'optimal values for font size 16, to be adapted depending on font size
    10. squiggly_brush.ViewportUnits = BrushMappingMode.Absolute
    11. squiggly_brush.TileMode = TileMode.Tile
    12. squiggly_brush.Drawing = New GeometryDrawing(Nothing, path_pen, path_geometry)
    13. Dim squiggly As TextDecoration = New TextDecoration(TextDecorationLocation.Underline, Nothing, 1.5, TextDecorationUnit.FontRecommended, TextDecorationUnit.FontRecommended)
    14. squiggly.Pen = New Pen(squiggly_brush, 6)
    15. Dim wavy As New TextDecorationCollection
    16. wavy.Add(squiggly)
    17. 'und in die RTB eingesetzt:
    18. Dim para As New Paragraph
    19. para.Inlines.Add(New Run("Teststring") With {.FontSize = 16, .TextDecorations = wavy})
    20. RTB.Document.Blocks.Add(para)


    EDIT 2: Abstand zum Text auf 1.5 geändert, da die Linie sonst bei 2 in den unteren Text reinfällt.

    EDIT 3: ViewPort-Werte an Schriftgröße angepasst
    Bilder
    • Wellenlinie funktioniert.png

      9,98 kB, 1.152×648, 30 mal angesehen
    :!: Leider hab ich nicht immer Zeit zum Programmieren, da es eher ein Hobby ist. Falls ich mal im Forum ne Frage stelle und länger nicht antworte, nicht böse sein: Ich bin dann entweder beruflich oder mit der Familie zu sehr eingespannt oder einfach zu müde. Das kann erfahrungsgemäß auch mal über Wochen dauern, aber ich melde mich immer und setze die Frage ggf. auf beantwortet.

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „Translating-IT“ ()

    Wenn du ein wenig mit dem Viewport spielst (insbesondere, wenn du die letzten beiden Ziffern erhöhst), kannst du auch dafür sorgen, dass die Linie etwas durchgängiger ist und sogar, dass nur eine auftaucht :)

    Hiermit habe ich das optisch schönste Ergebnis erzielt (meiner Meinung nach)
    womit? Oder bezieht sich das hiermit auf die leeren Zeilen. ;) Die schauen ja wirklich schön aus. Vor allem diese Pixelführung … O:)

    Edit: hab auf Dein Anraten hin noch ein bisschen damit rumgespielt und bin auf dieses Ergebnis gekommen. Das scheint perfekt zu passen.

    VB.NET-Quellcode

    1. squiggly_brush.Viewport = New Rect(0, 0, 7.8, 5.2)


    Auf welche Werte bist Du gekommen?

    :!: Leider hab ich nicht immer Zeit zum Programmieren, da es eher ein Hobby ist. Falls ich mal im Forum ne Frage stelle und länger nicht antworte, nicht böse sein: Ich bin dann entweder beruflich oder mit der Familie zu sehr eingespannt oder einfach zu müde. Das kann erfahrungsgemäß auch mal über Wochen dauern, aber ich melde mich immer und setze die Frage ggf. auf beantwortet.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Translating-IT“ ()

    VB.NET-Quellcode

    1. ​squiggly_brush.Viewport = New Rect(0, 0, 6, 10)


    Allerdings: Wenn du die Font-Size änderst... sieht die Einstellung auch wieder unschön aus... es ist also noch keine allgemein gültige Einstellung und müsste angepasst werden. Aber vielleicht kann man das noch dynamischer erstellen
    Ja, das wollte ich auch gerade schreiben. Habe gerade auf 12 umgestellt, und es schaut mit den neuen Werten wieder aus wie vorher. Wenn ich also die Schriftgröße ändere, sollte ich entsprechend die Viewport-Werte auch anpassen.
    Was etwas blöd ist, wenn ich dem Benutzer die Möglichkeit gebe, die Schriftgröße frei zu definieren. Oder entsprechend die Schriftgröße vorher abfragen und jeweils die durch Testen ermittelten Viewport-Werte automatisch anpassen lassen. Mal schauen, wie ich das löse. Das wäre dann eher reine Kosmetik und zurzeit nicht so wichtig. Den schwierigsten Teil haben wir hiermit geschafft.

    Ich danke Dir sehr für die Unterstützung und Hilfe.

    EDIT: evtl. sogar je Schriftart Viewport-Werte extra anpassen, da jede Schriftart ja unterschiedliche Größen und Breiten in pt verwendet?
    :!: Leider hab ich nicht immer Zeit zum Programmieren, da es eher ein Hobby ist. Falls ich mal im Forum ne Frage stelle und länger nicht antworte, nicht böse sein: Ich bin dann entweder beruflich oder mit der Familie zu sehr eingespannt oder einfach zu müde. Das kann erfahrungsgemäß auch mal über Wochen dauern, aber ich melde mich immer und setze die Frage ggf. auf beantwortet.
    Ja, generell könnte man ja eine Collection erstellen, in der die Viewports enthalten sind und die werden je nach Schriftart/größe abgegriffen udn ausgewählt. Aber das sollte nun, da du das eigentliche hast, ja keine Schwierigkeit mehr bereiten :)

    Sehr gern :) Und wer weiß, eventuell habe ich ja nun auch bald eine Verwendung dafür :P
    Ja, so ähnlich hatte ich mir das auch gedacht. Andere Frage. Wo kann ich diese ganzen Collections am Besten definieren? Derweil habe ich sie direkt in der Funktion definiert, wo sie verwendet werden. Nimmt, m. E. nur unnötig Platz dort weg.
    Und wie schaut es aus, wenn ich evtl. eine DataTable in ein DataGrid einsetzen will. Wie bekomme ich die Formatierung auf bestimmte Strings angewendet? Bin nämlich gestern drauf gekommen, dass ich evtl. eine DT brauchen könnte, ist aber noch nicht sicher.
    :!: Leider hab ich nicht immer Zeit zum Programmieren, da es eher ein Hobby ist. Falls ich mal im Forum ne Frage stelle und länger nicht antworte, nicht böse sein: Ich bin dann entweder beruflich oder mit der Familie zu sehr eingespannt oder einfach zu müde. Das kann erfahrungsgemäß auch mal über Wochen dauern, aber ich melde mich immer und setze die Frage ggf. auf beantwortet.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Translating-IT“ ()

    Kann jetzt übrigens auch ganz einfach auf eine Selection angewendet werden:

    VB.NET-Quellcode

    1. rtb_targettext.Selection.Select(foundRange.Start, foundRange.End)
    2. rtb_targettext.Selection.ApplyPropertyValue(Inline.TextDecorationsProperty, wavy)
    :!: Leider hab ich nicht immer Zeit zum Programmieren, da es eher ein Hobby ist. Falls ich mal im Forum ne Frage stelle und länger nicht antworte, nicht böse sein: Ich bin dann entweder beruflich oder mit der Familie zu sehr eingespannt oder einfach zu müde. Das kann erfahrungsgemäß auch mal über Wochen dauern, aber ich melde mich immer und setze die Frage ggf. auf beantwortet.

    Translating-IT schrieb:

    Ja, so ähnlich hatte ich mir das auch gedacht. Andere Frage. Wo kann ich diese ganzen Collections am Besten definieren? Derweil habe ich sie direkt in der Funktion definiert, wo sie verwendet werden. Nimmt, m. E. nur unnötig Platz dort weg.
    Und wie schaut es aus, wenn ich evtl. eine DataTable in ein DataGrid einsetzen will. Wie bekomme ich die Formatierung auf bestimmte Strings angewendet? Bin nämlich gestern drauf gekommen, dass ich evtl. eine DT brauchen könnte, ist aber noch nicht sicher.


    Tatsächlich gibt es hierfür keinen "richtigen Weg" Du kannst es als Funktion dort platzieren, dann ist es aber mühsam, wenn du es später mal woanders brauchst.

    Du kannst eine neue, eigens hierfür erstellte Klasse nutzen. Dann musst du sie immer instanzieren.

    du kannst eine Shared Methode erzeugen, die das zur Verfügung stellt, dann musst du immer auf deine aktuelle Klasse verweisen, in der es liegt.

    Du kannst eine Shared Klasse erzeugen, die das zur Verfügung stellt. Dann musst du diese referenzieren (dieses halte ich - meiner Meinung nach - für die beste Möglichkeit, da du es auch besser Trennen und unterscheiden kannst)

    Wenn du eine eigene Klasse hierfür schreibst zum Beispiel die Klasse "SpecialTextFormats" und die hat mehrere shared Methoden wie "GetWaveUnderline", "GetWaveStrikethrough", "GetDottedOverline", etc. dann weiß man direkt, worum es sich bei der Klasse handelt und man hat alle TextFormationen in dieser Klasse und kann sie global abrufen.

    Aber letztendlich kommt es immer darauf an, wie umfangreich es ist und wie oft und in welcher Reichweite du sie brauchst.
    für die unterschiedlichen Schriftgrößen habe ich das hier gebastelt (es sind noch nicht alle angepasst bzw. perfekt).

    insofern es nur die Größe ist, die maßgebend ist, und nicht auch noch die Schriftart (sonst muss noch ein If je Art eingebaut werden):

    VB.NET-Quellcode

    1. Dim font_size As Double = rtb_targettext.FontSize
    2. Dim doub_rect1 As Double
    3. Dim doub_rect2 As Double
    4. Dim doub_rect3 As Double
    5. Dim doub_rect4 As Double
    6. If font_size = 8 Then
    7. doub_rect1 = 0
    8. doub_rect2 = 0
    9. doub_rect3 = 7.8
    10. doub_rect4 = 2.76
    11. ElseIf font_size = 9 Then
    12. doub_rect1 = 0
    13. doub_rect2 = 0
    14. doub_rect3 = 7.8
    15. doub_rect4 = 3.06
    16. ElseIf font_size = 10 Then
    17. doub_rect1 = 0
    18. doub_rect2 = 0
    19. doub_rect3 = 7.8
    20. doub_rect4 = 3.36
    21. ElseIf font_size = 11 Then
    22. doub_rect1 = 0
    23. doub_rect2 = 0
    24. doub_rect3 = 7.8
    25. doub_rect4 = 3.66
    26. ElseIf font_size = 12 Then 'ok
    27. doub_rect1 = 0
    28. doub_rect2 = 0
    29. doub_rect3 = 7.8
    30. doub_rect4 = 4.1
    31. ElseIf font_size = 13 Then
    32. doub_rect1 = 0
    33. doub_rect2 = 0
    34. doub_rect3 = 7.8
    35. doub_rect4 = 4.26
    36. ElseIf font_size = 14 Then 'ok
    37. doub_rect1 = 0
    38. doub_rect2 = 0
    39. doub_rect3 = 7.8
    40. doub_rect4 = 4.56
    41. ElseIf font_size = 15 Then 'ok
    42. doub_rect1 = 0
    43. doub_rect2 = 0
    44. doub_rect3 = 7.8
    45. doub_rect4 = 4.84
    46. ElseIf font_size = 16 Then 'ok
    47. doub_rect1 = 0
    48. doub_rect2 = 0
    49. doub_rect3 = 7.8
    50. doub_rect4 = 5.14
    51. End If
    52. 'angewendet auf:
    53. squiggly_brush.Viewport = New Rect(doub_rect1, doub_rect2, doub_rect3, doub_rect4)
    :!: Leider hab ich nicht immer Zeit zum Programmieren, da es eher ein Hobby ist. Falls ich mal im Forum ne Frage stelle und länger nicht antworte, nicht böse sein: Ich bin dann entweder beruflich oder mit der Familie zu sehr eingespannt oder einfach zu müde. Das kann erfahrungsgemäß auch mal über Wochen dauern, aber ich melde mich immer und setze die Frage ggf. auf beantwortet.
    Um das etwas zu verkürzen und übersichtlicher zu gestalten noch ein paar Tipps:

    Statt If-elseif-...-else böte sich hier eine Select Case Schreibweise an.
    Und wenn du es als Funktion schreiben würdest, könntest du einige Zwischenschritte sparen:

    VB.NET-Quellcode

    1. Public Shared Function GetViewport(_FontSize As Double) As Rect
    2. Select Case _FontSize
    3. Case 8
    4. Return New Rect(0, 0, 7.8, 2.76)
    5. Case 9
    6. Return New Rect(0, 0, 7.8, 3.06)
    7. Case 10
    8. Return New Rect(0, 0, 7.8, 3.36)
    9. Case 11
    10. ...
    11. End Select
    12. End Function
    13. 'angewendet:
    14. squiggly_brush.Viewport = GetViewport(10)


    Spart Code ein und dient irgendwie auch der Übersichtlichkeit, da ich nun sofort sehe, welche Rect zurückgegeben werden

    ja, stimmt. Ich hatte vergessen dazuzuschreiben, dass ich es nicht nur für eine Formatierung hernehmen, sondern mehrere unterschiedliche Formatierungen (derzeit 4, können aber auch noch mehr werden) diese Werte benötigen. Dazu kommt, dass ich mit Case immer wieder Probleme habe (Fehler bei der Ausführung auftauchen) und es daher zu vermeiden versuche.
    :!: Leider hab ich nicht immer Zeit zum Programmieren, da es eher ein Hobby ist. Falls ich mal im Forum ne Frage stelle und länger nicht antworte, nicht böse sein: Ich bin dann entweder beruflich oder mit der Familie zu sehr eingespannt oder einfach zu müde. Das kann erfahrungsgemäß auch mal über Wochen dauern, aber ich melde mich immer und setze die Frage ggf. auf beantwortet.
    ​Dazu kommt, dass ich mit Case immer wieder Probleme habe (Fehler bei der Ausführung auftauchen) und es daher zu vermeiden versuche.
    Aber gerade dann wäre es doch gut, es zu verwenden. Denn nur so kannst du es schließlich üben. Und falls mal was nicht funktioniert, dann sind hier jede Menge Leute, die unterstützen können und auch möchten