WPF TextBox disable break on special characters - c#

I have a TextBox defined like this:
<TextBox Text="{Binding License.LicenseKey}"
HorizontalContentAlignment="Left"
TextAlignment="Justify"
Width="350"
Height="100"
Margin="10,0,0,0"
TextWrapping="Wrap" />
Currently a long string will break on special characters:
I would prefer it to simply break on any character once it reaches the end of the TextBox like this:
Is there a way to disable the stock breaking that a TextBox uses? I have tried various options for TextAlignment and HorizontalContentAlignment to no avail.

You could add a zero-width space (U+200B) after each character which would allow a break at any position. You would need to define a property in your view model and bind to it, and have the getter do this transformation so that it is displayed with line breaks, e.g.:
string SomeProperty
{
get { return String.Join(string.Empty, License.LicenseKey.Zip(new string('\u200B', License.LicenseKey.Length), (x, y) => x.ToString() + y)); }
set { Model.LicenseKey = value?.Replace("\u200B", string.Empty); }
}
However I don't know what would happen to the cursor position.

This is exceptionally messy due to limited options on the TextBox's TextWrapping property.
See this forum post to explain the U+200B comment below your question. However, that doesn't work for you because you DON'T want it to break. And if there's a library of standard non-breaking versions of characters, I've been unable to dig it up.
The only way I see this working is to use a fixed-width font, keeping track of how many characters are entered alongside the capacity of the box, and adding your own newline when that capacity is reached.

Related

WPF: How to use an integer (from C#-Code) inside a TextBlock?

So basically I have an integer textlength and it has a number of symbols. I then want to output the number of symbols onto a TextBlock/Label, so that the user can see, how many symbols he used. Is there a way of implementing this without "Binding"? I really dont know much about binding, but if it is necessary to use it, it is alright as well!!
Here is my simple code:
C#:
...
var textlength = text.Length;
...
XAML:
<TextBlock x:Name="MyTextBlock" Width="30" Height="28" Text=" . . . " />
I want the TextBlock to operate just as a usual console --> output the value of the textlength, by saying: "The number of symbols: ..."
Thank you a lot in advance!
The easiest way of doing this is by implementing your own DependencyProperty. I haven't touched WPF in a few years, but if I remember correctly, it should look something like this:
public static readonly DependencyProperty TextLengthProperty = DependencyProperty.Register(
"TextLength", typeof(int),
typeof(YourControlType)
);
public int TextLength
{
get => (int)GetValue(TextLengthProperty );
set => SetValue(TextLengthProperty , value);
}
And the binding would look something like this:
<TextBlock Text={Binding Path=TextLength, ElementName=nameOfParentControl}/>
Then you can directly update the TextLength property, and the TextBlock will be updated automatically.
I haven't tested this code, but it should give you a rough idea of what you need to do. Also, here's the documentation about data binding and custom dependency properties.
If you really want to avoid data binding, you could manually update the content of the TextBlock in an event to reflect the new value of text.Length. But keep in mind that this is not a recommended way of doing it, and learning about bindings instead will benefit you in the future!

How To surround a string in Quotation Marks in Xamarin.Forms

So I have a label which is bound to some text in my view model like so:
<Label VerticalOptions="Center" Text="{Binding Note, StringFormat='"{0}"'}" Style="{StaticResource ListItemSubTitleStyleDefault}" LineBreakMode="WordWrap" FontAttributes="Italic"/>
And I am trying to get the note to be surrounded in quotation marks like so
"I am a Note"
looking at some WPF answers it suggested using the following in the StringFormat property '"{0}"'
But this doesn't seem to work. Does anyone know how to surround a Labels text in quotation marks in Xamarin.Forms?
As you've seen, Xamarin.Forms is different from WPF for this case. For Xamarin, do this:
<Label VerticalOptions="Center" Text="{Binding Note, StringFormat='{}"{0}"'}" .../>
In order to prevent the runtime from ignoring the double quotes, the first double quote either has to be escaped (as above), or it can't immediately follow the single quote (see below).
So for example, throwing in a space in between works as well:
<Label VerticalOptions="Center" Text="{Binding Note, StringFormat=' "{0}"'}" .../>
With this latter solution, there will be at least one character rendered before the double quote.
On the code from your ViewModel you can also do this:
string _note;
public string Note => string.Format("\"{0}\"", _note);
I hope this helps.

Need assistance displaying multiple lines of code from a list in a WPF textbox

I have a list that pulls data from a feedservice and generates a group of names. I'm trying to place three of these names based on time inside of a text box. I have everything working but i'm having issues with formatting.
NextInLine.Text = max3?.Select(x => x?.AgentName).ToList().FirstOrDefault() ?? string.Empty;
This will display the name of three people in the format last-first. currently it displays one person name and sometimes will blink and show the other two. I would like all three names to appear on separate lines underneath of each other in the order it is provided in the list. Can any assist me with formatting. if needed I can add more code on the creation of the list.
XAML:
<TextBlock x:Name="NextInLine" FontFamily="segoe ui" FontSize="20" Margin="0,205,0,0" Height="30" VerticalAlignment="Top" HorizontalAlignment="Right" Width="186" Grid.ColumnSpan="2" TextAlignment="Center" TextWrapping="Wrap" Loaded="DisplayNumber_Loaded" Foreground="White" FontWeight="Bold"/>
Try this:
NextInLine.Text = string.Empty;
foreach (var item in max3)
NextInLine.Text += item.AgentName + Environment.NewLine;
Well, if you want all three names, you certainly don't want to be calling .FirstOrDefault() on the sequence, because that just gives you the first one. And you don't need to call .ToList() on it, because you're not keeping the results around.
All you really want to do is select the name of each agent object in the sequence, and join them with newlines. I don't think you need the "null-conditional" ?. operator either, if I correctly recall how max3 came to be from your previous questions. max3 should never be null, though it might have two, one, or even zero items in it. And we selected the items in it (if any) based on their properties, so the items themselves can't be null either.
NextInLine.Text = String.Join("\n", max3.Select(x => x.AgentName));
Think of it like so:
IEnumerable<String> names = max3?.Select(x => x?.AgentName);
String text = String.Join("\n", names);
NextInLine.Text = text;

Span-Elements in FormattedString appear to be trimmed

I am trying to put some formatted text in a view (an imprint, for what it's worth) with a Label with an formatted text. Text formatting works as intended, but whenever I try to add whitespace characters to the end of a span element within the formatted text these appear to be trimmed. This holds true for normal spaces, non-breaking spaces and CR/NL so far. Anyway, when in the middle of a string, nothing is removed.
This renders the label unusable for me (at least for this use-case), since I won't be able to format my text properly. Is there anything I have missed? I did not find anything about this matter in the web and in the documentation. Is the approach taken completely wrong, or is this a bug in Xamarin? (For that matter, the version used is 2.3.2.127)
This renders the label unusable for me (at least for this use-case), since I won't be able to format my text properly
It's not entirely clear why you would try to achieve this formatting with trailing whitespace.
Have you tried using margin or padding around the label?
https://developer.xamarin.com/guides/xamarin-forms/user-interface/layouts/margin-and-padding/
Using whitespace characters for element spacing is generally not a good practice.
The solution to this is to use inline Text="..." rather than enclosing the text between an opening and closing tag. For example, this preserves the spaces:
<FormattedString.Spans>
<Span Text="You have " />
<Span Text="{Binding Points}" />
<Span Text=" points." />
</FormattedString.Spans>
But this trims whitespace:
<FormattedString.Spans>
<Span>You have </Span>
<Span Text="{Binding Points}" />
<Span> points.</Span>
</FormattedString.Spans>

How to create multiline textbox which shows apostrophe before each line

I want a multiline textbox which shows apostrophes before and after each line.
So that the textbox looks like:
" Hello this "
" is a funny "
" string test "
Or for example:
// This is
// a muliline
// comment.
Edit: These special characters must be readonly and if the user copies text from the textbox these characters should not be included.
This is very easy using two textboxes laid directly over one another. The rear one is a normal textbox with extra padding and transparent text. The front one has your extra characters but has its borders hidden and is IsHitTestVisible=False and Focusable=False so it doesn't interact with the user. The user interacts exclusively with the rear textbox but the front textbox is the one that displays the text. A binding with a value converter keeps the front textbox displaying exactly what the rear textbox displays, plus the extra characters.
This is how it would look:
<ControlTemplate x:Key="TextBoxWithExtraCharacters" TargetType="{x:Type TextBox}">
<ControlTemplate.Resources>
<!-- Remove the border from the inner textboxes -->
<ControlTemplate TargetType="{x:Type TextBox}">
<Decorator x:Name="PART_Content" />
</ControlTemplate>
</ControlTemplate.Resources>
<!-- Now add our own border -->
<Border
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="true">
<!-- Scrolling must happen at this level so both text boxes scroll simultaneously -->
<ScrollViewer>
<Grid>
<!-- Rear textbox provides editing and user interaction but the text is transparent -->
<TextBox
Margin="10,0,10,0"
Foreground="Transparent"
Text="{Binding Text, RelativeSource={RelativeSource TemplatedParent}"
Background="{x:Null}"
IsReadOnly="{TemplateBinding IsReadOnly}"
IsUndoEnabled="{TemplateBinding IsUndoEnabled}"
AcceptsReturn="{TemplateBinding AcceptsReturn}"
AcceptsTab="{TemplateBinding AcceptsTab}"
/>
<!-- Front textbox displays modified text but does not interact with user -->
<TextBox
IsHitTestVisible="false"
Focusable="false"
Text="{Binding Text, RelativeSource={RelativeSource TemplatedParent},
Converter={x:Static ExtraCharacterConverter.Instance}"
Background="{x:Null}"
IsReadOnly="{TemplateBinding IsReadOnly}"
IsUndoEnabled="{TemplateBinding IsUndoEnabled}"
AcceptsReturn="{TemplateBinding AcceptsReturn}"
AcceptsTab="{TemplateBinding AcceptsTab}"
/>
</Grid>
</ScrollViewer>
</Border>
</ControlTemplate>
ExtraCharacterConverter is a simple IValueConverter class that implements the Convert method by taking the given string, appending quotes or // or whatever to it, and returning the result.
Note that I hard-coded a left and right margin of 10 units on the rear textbox, which assumes a particular width for the quote characters. This should be exactly the width of the added characters to make the text line up correctly. You want to get this right, or your caret and text selection positioning will be wrong. Also note that the correct value will change as you vary your font size and your choice of extra characters.
An easy alternative to hard-coding the margin would be to set it to a multi-binding on FontSize, FontFamily, FontWeight, etc, then use a IMultiValueConverter to compute the proper margin given this these values.
Note: This solution is slighly unsatisfactory when it comes to the color scheme for text selection. This can be fixed, but it requires a more complex solution: The rear text box is the same but its text is not invisible. The front text box is replaced with a RichTextBox (or TextBlock) whose content is computed dynamically to be the text with extra characters, but the regular text transparent. Because it is a RichTextBox the extra characters can be visible while the others are transparent.
Can you not simply create a user defined textbox using inheritance with the multiline property set to true, and some special code on the text changed event to check the first and last index on each line to ensure it has an apostrophe there? or if there is no way to iterate lines, can you just watch the character before and after every chr(11) or chr(13)?
This wouldn't be difficult with winforms, i'm not sure about WPF however.
~~~~~~~~~~~~~~~~~~~~~~~~~Edit 1: 11/25/2009 9:12 AM CT~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you would like it so that the user cannot edit or mess with the quotes, then you could write specific code in the KeyPressed event handler (or override the OnKeyPressed function if you are doing an inherited control) to keep them from adding characters before or after a chr(11) or chr(13), and add it back immediately if they attempt to delete it, and cancel invalid keystrokes.
I've written code similar to this in VB .NET for a money text box field. It may help you to understand what i'm talking about, and it may assist you in what you are doing:
Protected Overrides Sub OnMouseClick(ByVal e As System.Windows.Forms.MouseEventArgs)
If Me.SelectionStart = 0 Then
Me.SelectionStart = Me.Text.Length
End If
End Sub
Protected Overrides Sub OnTextChanged(ByVal e As System.EventArgs)
If Not Me.Text.IndexOf("$") = 0 Then
Me.Text = "$" + Me.Text.Replace("$", "")
End If
If Me.SelectionStart = 0 Then
Me.SelectionStart = Me.Text.Length
End If
End Sub
Protected Overrides Sub OnKeyPress(ByVal e As System.Windows.Forms.KeyPressEventArgs)
If NOT ((Char.IsDigit(e.KeyChar) Or (e.KeyChar = CChar(".") And Not Me.Text.Contains(".")) Or Char.IsControl(e.KeyChar)) And (Not Char.IsDigit(e.KeyChar) Or (Me.SelectionStart <= Me.Text.IndexOf(".") + 2 Or Me.Text.IndexOf(".") = -1))) Then
e.Handled = True
End If
End Sub
I'd say your best bet is to implement your own textbox (inherit from textbox itself as a base, so you get all of the functionality for free) and override the drawing code and writing out each line yourself (pre/post-pending the apostrophes as you write out each line).

Categories