How to render whitespaces as dots in WPF RichTextBox? - wpf

I need the way to render regular space, nonbreaking space and some other formatting characters (like left-to-right mark) like MS Word renders them, when you choose to show non-printable characters.
I tried two approaches:
1) Replace characters with rarely used characters.
It works, but in this case we loose "nonbreaking" behavior of nonbreakable space (and LTR and RTL marks also stop working)
2) Use the custom font
It allows to preserve special behavior of nonbreaking space and LTR/RTL marks, but for some strange reason WPF renders nonbreaking space with usual space glyph.
WinForms RichTextBox renders text with the same font correctly.
This problem could be solved with applying different font with different space glyph for spaces and nonbreaking spaces, but LTR and RTL marks are not rendered at all even if I add glyph for them.
Have you any ideas how I could render that characters with visible glyph preserving their "LTR", "RTL", "nonbreaking" behavior?

I didn't try anything similar until now, but I can think of two options:
Warning -> I didn't try it out
The first method:
Create a subclass of UIElement
Get the Style with ControlTemplate for the Richtextbox and add it to App.xaml
Add an instance of your subclassed UIElement within the inner Panel of the Scrollviewer from the RichTextBox ControlTemplate
Make the RTBox available to a dependency property in your class via DataBinding in the ControlTemplate (if possible) or any other way that does the job
In your UIElement subclass, you iterate through characters of the document
Draw a symbol in your Adorner for each space and LineBreak you encounter
Get the Rect of a character at a specific position with the RichTextBox. Use this rect for placing the symbols.
The advantage of this Method is that you have a clean separation and don't need to subclass the RTFBox, but you won't be able manipulate the width of the spacing to make room for larger symbols. Also, other developers need to know that they need that Style in order to gain that functionality.
The second method:
Create a Custom Adorner
Decorate the RTBox with the custom Adorner
From the Adorner, you should be able to access the Child RTBox
In your UIElement subclass, you iterate through characters of the document
Draw a symbol in your UIElement for each space and LineBreak you encounter
I remember that there is a possibility to get the Rect of a character at a specific position with the RichTextBox. Use this rect for placing the symbols.
It's also without subclassing the RTBox. You also can't adjust the spacing. In contrast to method 1, other developers will immediatly recognize that this functionality has been added. The one disadvantage is that you will have to handle scrolling too.

You can try insert near LTR/RTL visible glyph instead of replace that.

Store all of the values as their special characters. It sounds like your printing functions need to handle a) what kind of output the user wants, b) interpret your data array/massive string of characters and spit out the values with regard to what the user wants to see. You don't give too many details on how your things are stored but this would be a very reasonable way to go about things.

Related

How does one find the caret position (in screen-space or form-space) in a WPF textbox?

As the title suggests, how do I find the caret position of a WPF textbox in screen or form-space coordinates? So far, I've only been able to find how to get the character position of the caret in the textbox.
Perhaps I'm getting ahead of myself though, because really, I'm trying to ensure that the current caret position of the selected TextBox (of dynamic height) contained within a DataGrid is visible to the user. So, if there's a way to do this without knowing the coordinates of the caret, then I'm all ears. So far, I've tried calling the DataGrid's ScrollIntoView method, but this can fail if the TextBox is taller than the available screen space.
I don't believe you can do it natively, but you call use interop to call the Win32 GetGUIThreadInfo(). See here for an example: How to call GetGUIThreadInfo in c#
I would suggest something but I don't know if it is applicable in your case. I needed to create a triangular caret to replace the vertical-line caret of a WPF textbox. I control its location with a translate transform and it is always following the default textbox caret. In this way you know where is your new caret is inside the text box (by knowing the X and Y of its translate transform) and then you can use PointToScreen to convert it to screen coordinates.

Multiline Textbox Vertical Spacing (Winform)

I am using the standard textbox control on a Windows form. I want to display the text VERTICALLY rather than horizontally. To accomplish this I set the multiline property to true, the TextAligh property to center and used the lines property to input each character as a separate array element. So far, so good.
I see the text displayed the way I want but would like to reduce the vertical spacing between lines without reducing the font size. Can it be done? If so, how?
It can be done, but not by the default options on a standard textbox.
You would probably need to override the Paint event and draw the text yourself, but it would get very ugly, and would essentially be reinventing the standard Paint method.

Is there any way to merge margins in WPF?

In HTML, for a table (at least), one can style the element so that margins are merged. I.e. two adjacent rows both have top and bottom margins of 10, so the gap between these two rows will be 20. When their margins are merged, the gap is only 10.
Is there any way to achieve this in WPF?
There is no easy way to do this, and when you look at how WPF handles layout you'll see why, but also see that there is a hard way if you're up to it.
As you can see from the WPF source code for FrameworkElement, the MeasureCore sealed override method (which prevents us from overriding it further) adds the element's margins before returning with its desired size. Annoyingly, they seem to have a BypassLayoutPolicies option which would prevent this, but for reasons possibly ranging from short-sighted to sadistic, they made this internal so it's not an option. Thus the fully margined size of the element is what always winds up being assigned to DesiredSize, which is basically what all layout panels (StackPanel) etc. naively use to arrange the items during ArrangeOverride.
But therein is the solution, if you're willing to subclass all the panels and override their MeasureOverride and ArrangeOverride. Knowing the margin values of two adjacent children you could collapse their respective right/left or bottom/top margins together during the measure and arrange passes, by just subtracting the duplicative portion of the margin from their `DesiredSize's.
But if you're gonna subclass anyway, another option, which I would consider cleaner and a better practice overall, is to add a Spacing property to your subclassed Panels, which exists in the WinUI version of StackPanel. This would require you to either ensure that your child items all have zero margins, or to subtract their actual margin values out from their DesiredSize's. You would then add this spacing instead between the items during the arrange pass.
StackPanel is easy enough to extend this way as both passes are very simple. Grid, unfortunately, is a lot more complicated. VirtualizingStackPanel is probably out of the question... So this is by no means a silver bullet, but given how common StackPanel is, even just extending that control would cover a whole lot of ground and lead to much cleaner layouts IMO.
If I had more reputation I'd mark this as a duplicate of Is it possible to emulate border-collapse (ala CSS) in a WPF ItemsControl? . It looks as if this is kludgeable (for a ListBox at least) using a DataTrigger to check the value of preceding entries and set borders accordingly for null values.

Silverlight 3 - Control over wrapping in TextBox

Ok I have the following problem in Silverlight. I have a control with 2 columns. On the left is a stack panel with line numbers and on the right is a textBox.
So when I write in textBox without wrapping turned on I can simply create the right count of numbers on the left, because I'm searching for '\r' in text.
But when I turn on wrapping I have no control over the count of lines in textBox.
Is there a way to get to that count? Or a way to know which line in textBox is going to wrap?
I hope you can understand what I'm trying to do.
There's one way to do this. You can simulate the word wrap operation in the background using a TextBlock. Here is a good link of the complete solution to this problem.
Extended TextBox control with MaxLines property
Is it not possible to create your items in code before they are passed to the view. This would enable you to bind a list of items to a listview and style them as you wish.
You need to user a value converter to count the number of char / lines and then trim that number if you wish to. Unless you use fixed width, you can't really count or calculte in advancet the size, since each application might be displayed differently (due to different sizing option).
There are two great sample chapters on Windows Phone and Silverlight for Windows Phone on the LearningWindosPhone.com site. There is great Windows Phone Trainng material , and dont forget the Windows Phone Develoeprs Blog
Yes there is a way to get the number of lines occupied by the text in the textbox. It's not that simple though 'coz you have to simulate the behavior of the word wrap in order to count/predict the number of lines generated as a result of a word wrap. I have the solution described here in detail.

Resizing Labels

I have a chart in WPF with a lot of labels. The text on these labels is dynamically loaded and subject to change. If I set the width just to auto, then these labels may overlap, which makes the text unreadable.
The chart support multiple sizes, so if it gets larger, then the bars are re sized and there is more space for text. Now I want to adjust the text to the space which is available. If it gets too small, I don't want to display the label anymore (a tooltip is available, so the user still gets the required information). Consider the string "Case 1, blah blah", there is probably not enough space to display the whole string, but just the first word. In this case I want the string to be "Case 1..", with .. indicating that there is some more information in the tooltip.
I can determine the length available for the string. But how can I determine the space a single letter will take? Of course I could also just re size the label, but then it would just cut off the string anywhere which is probably not helpful for the user (and looks ugly).
Any ideas?
If you can use TextBlocks instead of labels then they have a TextTrimming property which will do this for you to either the nearest character or the nearest word.
While you seem happy with the TextTrimming property, I'll edit this to add that the TextBox control has a GetRectFromCharacterIndex method that would allow you to find out the size on screen of one or more characters as long as the font settings matched your label. This might be useful if you wanted to trim at specific places in the label rather than the nearest character / word.
Not an expert in WPF, but I would think that you'll need to do this in code rather than XAML.
Start by obtaining the actual pixel width of the space available for the text.
Then look at the character set, dot pitch etc. utilised on the XAML front end and from there calculate the pixel width required per character.
You could also look at changing the character sizes as well as reducing the label length.

Resources