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).
Related
I want to display the text "1/min" in a label with reversed FlowDirection, i.e. RightToLeft. However, the text remains the same with either "1/min" or "min/1".
Test code:
<Grid>
<StackPanel>
<Label FlowDirection="RightToLeft">1/min</Label>
<Label FlowDirection="RightToLeft">min/1</Label>
</StackPanel>
</Grid>
Both labels show the same text, namely "min/1". I'm fairly certain that non-ascii chars cause this, but how do I get around that behaviour?
I have a problem with WPF. I need WPF only for changing font size. So, I want to make something like text editor but only with changing the Font Size. I need to have text box/ text block and a button ("Font Size") which when you click it opens a new textbox and you add the desire size of the text. After you add the number it binds it and applies it to the text.
I can not write the code and will be very grateful if someone helps me! Thanks in advance!
You can use the following :
Style TargetType="{x:Type Window}">
<Setter Property="FontSize" Value="15" />
/Style>
and then add the dynamic change :
Say, textbox1 is the textbox where you want to add size value..
TextBlock FontFamily="Arial" Text="Sample text" FontSize="{Binding TextSize}" />
or
Application.Current.MainWindow.FontSize = Textbox1.text.toInt32();
I have a TextBlock of Width 600 and Height 80 in my WPF 4.0 application. I would like to truncate text and append ... at the end, at runtime.
How can I approach it?
Is it a TextBox or TextBlock?
If it is TextBlock, then you can use:
In C#:
myTextBlock.TextTrimming = TextTrimming.CharacterEllipsis;
OR
In XAML:
<TextBlock Name="myTextBlock" Margin="20" Background="LightGoldenrodYellow"
TextTrimming="WordEllipsis"
FontSize="14"
>
But if it were a TextBox, then as per my knowledge, you can bind a ValueConverter to the textbox and return the trancated text(with dots : ...) into the text box but save the full text into the Tag property of the textbox. So that your original text is not lost.
But, as per my knowledge, it is not a good practice to apply text trimming on text boxes until there is a specific requirement.
I am trying to create an application to take notes for windows phone 8.1
I want to give the user,a notebook type of feel.
For this I have created the UI for notes, the XAML is:
<Grid Margin="0,12.333,0,-0.333">
<Grid.Background>
<ImageBrush ImageSource="Images/notebookpaper.jpg"/>
</Grid.Background>
<TextBox TextWrapping="Wrap" Background="{x:Null}" Text="" BorderBrush="{x:Null}" HorizontalAlignment="Left" Margin="60,96,0,0" VerticalAlignment="Top" Height="480" Width="340" BorderThickness="0" GotFocus="TextBox_GotFocus" LostFocus="TextBox_LostFocus" FontFamily="Arial" TextChanged="TextBox_TextChanged" AcceptsReturn="True" FontSize="24.8"/>
<TextBlock Text="Date : " HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Top" Margin="246,10,0,0" Height="20" Width="59"/>
</Grid>
The image notebookpaper.jpg looks like this:
When user types in the text in text box, it looks like:
The problem is that, some characters appear a little above the line, some exactly on the line etc. which looks odd. Also, when I try to scroll, UI appears as:
The text appears striked out, as only the text scrolls and not the background image.
Also I want to be able to provide user a list of 5-6 fonts out of which they can select which one to use for typing the notes.
What should I do, so that the text appears properly aligned and text scrolls properly.
Is there any other way to do this ?
It looks like you have two problems:
Varying line height
Scrolling doesn't match the lines
To solve the first problem, you can probably work with TextBlock.TextLineBounds, talked about a bit in this MSDN blog post and the TextLineBounds enumeration documentation. This only seems to apply to TextBlocks, so you might have to swap between a TextBlock and TextBox as users edit their text.
To solve the second problem, the TextBox styles and templates page has a lot of helpful info. It looks like you can make your ImageBrush the background of your control by overriding TextBoxButtonBackgroundThemeBrush. If that doesn't work when focused, you may have to take the entire template given on the linked page and edit it to put your image in the background (there's a lot of XAML, but you should just be able to put your image in BackgroundElement or just before it).
If it still doesn't scroll, you can try setting ScrollViewer.Background instead; if that doesn't work, you'll need to handle the ScrollViewer.ViewChanging or ScrollViewer.ViewChanged events (probably by overriding it) so that it you can transform the background image by the amount of pixels the scrollviewer has moved.
You can also find the ScrollViewer in your code-behind (and skip dealing with the template) by using VisualTreeHelper. This would allow you to set the background of the ScrollViewer and/or subscribe to its events. This however is more brittle than the other methods and is usually a last resort.
I am working with some RichTextBlock objects that contain InlineUIContainer elements. I would like to be able to select and copy all of the text including the text contained in the InlineUIContainer.
Currently, when I select all of the text in the block, the text contained in the InlineUIContainer objects are skipped.
Here is an example of what I'm creating:
<RichTextBlock IsTextSelectionEnabled="True">
<Paragraph FontSize="20">
<Bold>This text is selectable</Bold>
<InlineUIContainer FontFamily="Global User Interface">
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="11" VerticalAlignment="Top" Margin="0,0,-1,0">Super Script Text</TextBlock>
<HyperlinkButton ClickMode="Release" Style="{StaticResource NoMarginHyperlinkButtonStyle}">
Link
</HyperlinkButton>
</StackPanel>
</InlineUIContainer>
This text is also selectable
</Paragraph>
</RichTextBlock>
If I select all of the text from this piece of Xaml and copy/paste it in NotePad, I don't get the Super Script Text or the Link text.
Is there any way to get all of the text selected?
This is because HyperlinkButton is not part of the document API and in fact a UIElement wrapped in InlineUIContainer. There are 2 ways to handle this.
Switch to Windows 8.1 and Hyperlink which inherits from TextElement and copy will work just fine.
This is the hard way, if you must support this in Windows 8.
Remove the default Context menu items for the RichTextBlock and replace with your own Copy Command. Which should get the 2 TextPointers i.e. RichtextBlock.SelectionStart and RichTextBlock.SelectionEnd
Now with WPF we could get a TextRange within this range but winRT does not expose it, so you will need to do it in your code...
Get all the block within the RichTextBlock, and iterate through each to check if it's ContentStart and ContentEnd is within the RTB.SelectionStart and RTB.SelectionEnd if so then add them to a list.
Now it should be easy to extract all the Runs and Bold/Italics from this list and any InlineUIContainers hosting HyperlinkButtons.
2 This is not really a good way to go as it will be hard to allow for margins etc. on Paragraphs etc.