WPF RichTextBox automatically merges two adjacent Runs - wpf

I have a RichTextBox containing two Runs:
<RichTextBox>
<RichTextBox.Document>
<FlowDocument>
<FlowDocument.Blocks>
<Paragraph Name="par">
<Run Text="First"/>
<Run Text="Second"/>
</Paragraph>
</FlowDocument.Blocks>
</FlowDocument>
</RichTextBox.Document>
</RichTextBox>
When I iterate through the Inlines of the par, I see three Runs: "First", " "(space) and "Second". It's ok. But if I delete second " " Run (using Backspace key, for example) and then iterate through the Inlines of the par, I see only one "FirstSecond" Run. RichTextBox merges two remaining Runs into single Run. However, if "First" and "Second" Runs have different TextFont or TextWeight values, RichTextBox won't merge them and I'll see two distinct Runs: "First" and "Second".
Now my question: How can I preserve adjacent Runs from being merged automatically by RichTextBox?
I would like to get the behaviour similar to the one when Runs have different TextFont or TextWeight values, but visually their formats should be equal. I've tried to set different Tag values for the different Runs, but it didn't help. Maybe, there is some "logical" format, that doesn't influence the appearance of the Runs, but warns RichTextBox to distinguish them.

Though I haven't found a clear solution, there is a workaround. Run has the Typography property, which, in its turn, has the Int32 AnnotationAlternates property. This property defines the fine tuning of the outlook for the specific characters of the specific fonts. If this property isn't used as intended, it can be used as a "logical" format for a Run. As written in MSDN:
If the value of AnnotationAlternates is greater than zero and the
selected font does not support annotation alternates, the default form
of the letter is displayed.
In my application I use Segoe UI font, which, as it turns out, doesn't support annotation alternates, so this workaround works for me. If you use font that supports annotation alternates, you can try to use rather big values of the AnnotationAlternates property, maybe, it won't influence the appearance of the text.

Related

How to display backspace, shift, etc symbols in onscreen keyboard in WPF

TL;DR;
1.In WPF how can I display key symbols (e.g. backspace, as well as custom symbols that I will invent) so that they seamlessly sit alongside letters and numbers on other keys?
2.How can I apply a glow effect to the text on these keys so that letters, numbers, and symbols (e.g. backspace) glow in the same way?
Longer version;
I am writing an onscreen keyboard in WPF using a Border for the outline of each key and a TextBlock to display the text, for example the 'A' key might be defined as;
<Border>
<Border.Tag>
<KeyValue Key="A" Function="{x:Null}" />
</Border.Tag>
<TextBlock Text="A" />
</Border>
A function key, such as backspace, might be;
<Border>
<Border.Tag>
<KeyValue Key="{x:Null}" Function="{x:Static Functions.Backspace}" />
</Border.Tag>
<TextBlock Text="BACKSPACE" />
</Border>
For special keys such as Return, Backspace, Shift, Caps Lock, etc, I would prefer to display a symbol, for example ⏎ rather than "Return"/"Enter". I also have custom keys which will need a custom character that does not exist in the unicode character list.
I found that Unicode includes definitions for the standard characters (check out the below link which is very useful if you don't scroll down too far and crash your browser);
http://unicode-table.com/en/search/?q=return
This gives me ⏎ = U+23CE or ⏎ for return, for example.
My issues:
I will be using a font which may not include these extended characters. This article suggests that only the core characters in unicode are covered by most fonts;
http://www.typography.com/faq/question.php?faqID=41
I want to use custom symbols (which I will invent) so unicode characters couldn't meet my requirements completely anyway.
I am not sure where to start if I go down the route of creating vector graphics for the symbols. They will need to support a glow animation which will occur on all keys (letters, numbers and symbols) and will be triggered when a key is 'pressed'. BitmapEffects was obsoleted after .Net 3.5 as it software rendered. The article below suggests using the DropShadowEffect - how should I create the symbols so that I can use the same approach for making the keys glow?
OuterGlowBitmapEffect Alternative Without BitmapEffects
Thanks for reading and for any help you offer.
Julius
EDITTED to include a clearer example of how key values are stored in the key Tags.
It depends how your handling the key press event.
if you are binding to a command then you can use the command parameter to control what the key value actually is and thus breaking it from what is displayed.
Alternatively, if doing this in an event handler - use a button property, such as Tag which you can inspect in your handler.
Then replace your text box button contents with something else that can represent your custom keys, an image would work - a path would be better since that will support the same effects applied to your text box.
For the visual stuff I would look at adding icon images.
<Geometry x:Key="appbar_user_path">
F1 M 24,12C 27.5,12 29,14 28.4952,18.1979C 28.9462,18.4566 29.25,18.9428 29.25,19.5C 29.25,20.1818 28.7951,20.7574 28.1723,20.9397C 27.9121,21.8672 27.508,22.6882 27,23.3449L 27,26.5C 28.6667,26.8333 30,27 32,28C 34,29 34.6667,29.9167 36,31.25L 36,36L 12,36L 12,31.25C 13.3333,29.9167 14,29 16,28C 18,27 19.3333,26.8333 21,26.5L 21,23.3449C 20.492,22.6882 20.0879,21.8672 19.8277,20.9397C 19.2049,20.7574 18.75,20.1818 18.75,19.5C 18.75,18.9428 19.0538,18.4566 19.5048,18.1979C 19,14 20.5,12 24,12 Z
</Geometry>
For the On-Screen-Keyboard, I think you'll want to dig into TextCompositionManager and Help with the WPF TextCompositionManager events
static void SendTextCompenstation( string key )
{
var textcomp = new TextComposition( InputManager.Current, UiControl, key );
TextCompositionManager.StartComposition( textcomp );
}

TextTrimming with Ellipsis and a Colon

This is a relatively simple question:
I can trim a text with ellipsis using this:
<TextBlock Text="{Binding}" TextTrimming="CharacterEllipsis"/>
it would give me something along the lines of:
"This sentence is too long"
=>
"This sentence i..."
That's all great and dandy, but what I actually want is this:
"This sentence ...:" / "This sentence...:"
What I'm looking for is a colon after the ellipses. Is there a simple way to achieve this?
EDIT:
sorry for the confusion.
I want to change the default ellipsis string from '...' to '...:'. As well, I'm going to include a colon in the text string itself. This way, I'll always have the colon displayed. As well, everything should be on one line in every situation.
here are a couple of results that are acceptable:
short enough:
way too l...:
This works, but I needed to add some padding so that the colon always remains visible:
<TextBlock Padding="0,0,5,0" >
<TextBlock TextTrimming="CharacterEllipsis">Lorem ipsum dolor sit amet, consectetur adipisicing </TextBlock>
<TextBlock>:</TextBlock>
</TextBlock>
Use two TextBlocks with the ellipses example in the first and the colon in the second.
Update:
It looks like this is a relatively simple question with plenty of complications.
One may be tempted to have some TextBlocks, the first with the target text and another two displaying ":" and "...:" and switch between with a Visibility value converter them based on whether the first TextBlock had enough space to display all of its text. This has possibilities but has the potential for unstable layouts.
Having just implemented a custom panel I can imagine a possible solution involving one designed to hold three children which would be the three TextBlocks described abovel
A custom panel inherited from Panel should override two key methods: Measure and Arrange.
In the measure method all of the children should be measured.
In the arrange method check whether there is enough room to display the first two children and if so put them side by side. If there is not enough room display the first child sized to allow the third child room to display and set the third child right aligned.
Update:
I tried the custom panel and it worked except the the first TextBox is clips partial characters.
The ultimate solution for clean formatting would be a method which adjust the display string until fits within the allotted space with the appropriate suffix applied.
If you do not include the colon in your strings, you can use Binding.StringFormat:
<TextBlock Text="{Binding, StringFormat={}{0}:}" TextTrimming="CharacterEllipsis"/>
(I realize this is a very old question, but I happened to stumble on it, so I thought I'd throw this in for anyone else who follows.)

Soft hyphens in XAML?

does anybody have an idea whether it is possible to define "soft hyphens" or "soft linebreaks" in e.g. a TextBlock's text? Background: I would like to use TextWrapping="Wrap" on a TextBlock, but normally that won't do anything if the text contained in the TextBlock does not contain white space.
E.g.
<TextBlock TextWrapping="Wrap" Text="OneVeryLongWordThatDoesNotContainAnyWhiteSpaceAtAll" />
won't wrap if there is insufficient space. So I thought maybe there is a way to tell TextWrapping where the text may be wrapped.
I tried using the HTML ­ (soft hyphen) entity, but this is not allowed in XAML apparently (won't compile).
Cheers,
Alex
Alex,
what do you mean by "won't wrap if there is insufficient space"? I tried your example code and it actually does wrap (it will break on every single character if necessary) when adding Width="100" or limiting by it's margins etc.
Setting width to 100 i get the following result:
OneVeryLongWor
dThatDoesNotCon
tainAnyWhiteSpa
ceAtAll
When you limit the height (like Height="20"), it won't actually break of course, but you can add TextTrimming="WordEllipsis" to get a result like this:
OneVeryLongW...
But oh well, it doesn't answer your question about Soft Hyphens, they obviously don't work.
Best regards =)

TextBlock inside a Viewbox - strange rendering

This is a question regarding a very simple construction - I have the following XAML:
<Viewbox Height="100" Stretch="Uniform">
<TextBlock FontFamily="Georgia">My Cool Text</TextBlock>
</Viewbox>
This is quite simple to understand. Yet when I start the program I get strange blurry text (there are no bitmap effects anywhere in my project).
(left side - the designer view in VS2010, right side - the running application)
Does anyone have ANY suggestions about why this is happening??
While Jefim has correctly answered his own question, I wanted to explain why you get this behaviour when using this particular set of features. Jefim suggests that this is a bug in WPF, but it's not. The problem arises as a result of asking for WPF to do something impossible. It has to pick a compromise when you've asked for this impossible thing, and the result is what you see above.
The explanation is a bit long for a comment, which is why I'm putting it in a separate answer.
This example uses two mutually contradictory features of WPF. Those features are:
The ability to render visuals consistently at any scale
The ability to render text in the same way GDI32 renders text
You can't use both features at once. GDI32 renders text in a way that cannot be scaled consistently: if a particular piece of text at a certain font size happens to be 200 pixels wide, if you multiply the font size by 3, and render the same text in the same font family at that new font size, in GDI32 it probably won't be 600 pixels - it'll be close, but it will typically not be quite right.
GDI32 messes with the shapes and widths of characters in order to enhance the clarity and sharpness of the text. Specifically, it bends letters out of shape so that their features align better with the pixels on your screen. And where necessary, it will adjust the width of individual characters to be an exact number of pixels wide. Since this letter bending is all based around actual pixels, it bends text in different ways at different font sizes.
While that gives you nice sharp looking text, it looks absolutely horrible if you try to change the scale gradually. If you try to animate the font size of some text rendered in this fashion, the thing will seem to shimmer and shudder, because the adjustments made in the name of clarity end up being slightly different at each font size. Even if you're not animating, it can still produce poor results - if you have a single typeface shown at a number of sizes, it can look quite different at each size; if your application has a zoom feature, the character of the text can seem to change significantly as you zoom in and out. (And so can the layout. If you use Microsoft Word, you may have noticed that you sometimes get odd-looking extra wide spaces between certain words. This is the result of Word fighting with GDI32 - Word attempts to keep the on-screen layout as close as possible to how things will look when printing, which means it sometimes clashes with GDI32's grid fitting.)
So WPF offers a different approach to text rendering: it can render text in a way that is as faithful as possible to the original design of the font. This distorts the text less, and it means that you don't get discontinuities as you scale.
The downside is that the text looks blurry, compared to how text rendered by GDI32 looks. (The distortions made by GDI32 are all aimed at improving clarity.)
So in WPF 4.0, Microsoft added the ability to render text in the way GDI32 would. That's what TextOptions.TextFormattingMode="Display" does.
By turning on that option, you are saying "I don't need consistent scaling, and I'd prefer clarity, so generate the same pixels you would have done in GDI32." If you then go on to apply scaling, having told WPF you didn't need scalability, you get crappy results. WPF carefully generated a bitmap representation of the text exactly to your specifications, and you then told it to render that text at a different scale. And so it looks like what it is: a scaled bitmap of some text that was generated for a different resolution.
You could argue that WPF could do something different here: if you apply a scale transform in GDI32 you'd see different behaviour - you'd see the inconsistency at different scales described earlier. If you really want that effect in WPF you can get it by modifying the font size directly. But WPF doesn't prioritise getting that same effect - its goals are to make it possible to get GDI32-style crisp text when you really need it, and to provide consistent scaling by default.
And what you're running into here is the "consistent scaling". Turning on GDI32-style text rendering doesn't break consistent scaling: applying a scale factor (either directly, via a ScaleTransform or indirectly via a Viewbox) will change the dimensions of the visual by exactly the specified scale factor. If it were to re-generate the text visuals by grid fitting to the newly scaled size, the text would come out at a different width. That would actually cause the Viewbox problems: it applies a scale factor based on the content's natural size, designed to make it fit the available space. But if it re-did the grid fit after scaling, that would actually change the width. Because of the inconsistencies inherent in how GDI32 text rendering works, it might not even be possible for the ViewBox to find a suitable scale - it's possible to come up with a piece of text which, when rendered in a particular font, will never come out at 200 pixels wide. For some font sizes, the rounding inherent in grid fitting might bump the size down to, say, 198, and it might stick at that as you make tiny increments in the font size, until you go past some threshold at which point it might jump to 202 pixels.
For a Viewbox attempting to force the text to fit into exactly 200 pixels, that would be a problem. But Viewbox doesn't work that way - it uses WPF's consistent scaling, downstream of the point at which you chose the font size to which GDI32-style text rendering is working. So Viewbox will always be able to do what it is designed to do, but that is task that's fundamentally incompatible with GDI32-style text rendering.
So in short, WPF renders the text for the font size you requested, and then scales the result.
So you have to pick just one feature - you can't have both because that's simply impossible. Either don't attempt to render text in a context in which an arbitrary scale factor may be applied (e.g. Viewbox) or don't turn on GDI32-style text rendering. Otherwise, you get that weird pixelated text that you've encountered.
Ok, bug found. My Window style has the following setter:
<Setter Property="TextOptions.TextFormattingMode" Value="Display"/>
If I set it back to "Ideal" (which is the default value) then it renders the text inside the viewbox correctly. I would say that this is a bug inside WPF. Basically, if you try this:
<Viewbox Height="100" Stretch="Uniform" TextOptions.TextFormattingMode="Display">
<TextBlock FontFamily="Georgia">My Cool Text</TextBlock>
</Viewbox>
You will get the same result as in my initial picture.

How can we extract actual font family from a CompositeFontFamily applied to a run in WPF RichTextBox

A composite font family is a collection of FontFamilies. On applying the composite font to a run, appropriate font from its font-collection is applied depending on text.
How can we get which actual font is being used in a run on which a composite font has been applied?
EDIT2: Suppose I have a run
<Run Text="Some text with different unicode characters not available in applied FontFamily" FontFamily="Global User Interface"/>
Now if I check run.FontFamily it returns "Global User Interface", but actual font applied is one from the FontFamily collection of this composite font. So I want to find out which font it is?
EDIT1: One way I can think of is - to find it the way WPF applies a font. For each language, the composite font specifies a set of fonts corresponding to specified range of characters. So we can find each of the character in a run of text, then lookup the font corresponding to this character in the fontfamilymap for current language.
Is this the right way? Are there any cases where it may fail?
Is it the only way? Is there any API\straightforward way instead?
Thanks

Resources