Copying Xaml RichTextBlock text with InlineUIContainers - c#

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.

Related

Is it possible to bind to a property on the container of the Adorned Element?

In my WPF app we are using an adorner for displaying validation messages, in the particular case there is a single row grid that has multiple controls some of which have validation. The problem I'm having is that I want to force the width of the error message control to be the same as the grid but can't seem to find a way to reference that grid from the adorner template. Here is a sample of what I tried:
<ControlTemplate x:Key="Local_TopAdornedTemplateWide">
<StackPanel>
<AdornedElementPlaceholder x:Name="adornedElement"/>
<TextBlock MaxWidth="{Binding Path=ActualWidth, RelativeSource={RelativeSource FindAncestor, AncestorType=Grid}, ElementName=adornedElement}"
TextWrapping="Wrap"
Text="{Binding Converter={StaticResource Local_ValidationErrorMessageConverter}}"
Style="{DynamicResource Error_Text}"
Padding="2 1 0 0"
Visibility="{Binding ElementName=adornedElement, Mode=OneWay, Path=AdornedElement.IsVisible, Converter={StaticResource BooleanToVisibilityConverter}}"
/>
</StackPanel>
</ControlTemplate>
This causes the application to crash with an XamlParseException.
Ideally the solution would not be specific to a grid so that it would get the width of any container type, but for now grid is the only use case.
Edit:
Here is an example of another template we use in the application; this template would not work for my case as it would limit the error to be the width of a single column of the aforementioned grid:
<ControlTemplate x:Key="Local_TopAdornedErrorTemplate">
<StackPanel>
<AdornedElementPlaceholder x:Name="adornedElement"/>
<TextBlock MaxWidth="{Binding ElementName=adornedElement, Path=ActualWidth}"
TextWrapping="Wrap"
Text="{Binding Converter={StaticResource Local_ValidationErrorMessageConverter}}"
Style="{DynamicResource Error_Text}"
Padding="2 1 0 0"
Visibility="{Binding ElementName=adornedElement, Mode=OneWay, Path=AdornedElement.IsVisible, Converter={StaticResource BooleanToVisibilityConverter}}"
/>
</StackPanel>
</ControlTemplate>
Using snoop I captured the following two screenshots (I could not take one of the full stack to prevent posting anything proprietary)
This shot shows the grid I mentioned previously, within this it is the FinancialTextBox item that is being adorned
This shot shows two things, the item selected in blue is the highest ancestor of the grid in the previous shot, the yellow highlight is the Textbox from the content template
With those two it seems to be apparent that (based on information from Contango's answer) the two items aren't not in the same visual tree which would lead me to believe my question is not possible. However the second template I added (which does work) points that at least some visual information from the adorned element lives on in the place holder.
So now my question boils down to a) does this information include the parent of the adorned element and b) how can this be accessed via a binding on a different element?
This ended up being a lot simpler than the path I was trying to go down.
I was doing some reading on the AdornedElementPlaceholder class and came across this entry on MSDN and noticed that the class actually has a property called parent, with that I tried the following binding and it works perfectly:
MaxWidth="{Binding ElementName=adornedElement,
Mode=OneWay,
Path=AdornedElement.Parent.ActualWidth}"
WPF is quite powerful and flexible.
You can bind any property in any XAML tag to any property in any other XAML tag.
For example, you could write a test app that binds the Text property of an input box to the Text property of a label, so as you type something into the text box, the label would change automatically (assuming you use UpdateSourceTrigger=PropertyChanged). This is a direct XAML to XAML binding, with no C# in sight.
Similarly, you could bind the width of your error box to the width of the parent control, whatever that may be.
Google RelativeSource and AncestorType, this is a great link:
http://druss.co/2013/10/wpf-binding-examples/
See if you can grok how the Visual Tree and Logical Tree works in WPF, once you understand that, you will understand more of how binding works.
I'd also recommend using the free tool Snoop to look at the Visual Tree. XAML Spy is excellent, but not free.
Snoop can tell you if there is anything that has a bad binding at runtime (you set the filters up, and it will list all bad bindings).
You can use Snoop to get the full XAML path of your source (the XAML you wrote above), then get the full XAML path of the target (i.e. the ActualWidth of your Grid), then compare them: it may be quickly apparent that one is not the ancestor of the other, as they are on different branches of the visual tree, or that there is some other issue which is preventing a simple walk up the visual tree from working.
If you just want to get something working, as a proof of concept, try naming the target XAML grid using x:Name, and reference it by name instead of AncestorType.

Notebook-like background for a TextBox in a Windows Phone App

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.

How to create Image in runtime in windows phone?

I am trying to create custom menu which consists of text at least 2 textblock in one rectangle, which will act as button, For that purpose, May be converting the text into Image may be good idea to implement and serve my purpose to. so I want and Idea or code to create image during runtime, any suggestion ? If you have any sample code or link to refer??
if by "2 textblock in one rectangle" you mean text in two lines then try this
<Button>
<StackPanel>
<TextBlock Text="ABC"/>
<TextBlock Text="DEF"/>
</StackPanel>
</Button>

Textblock text selection

I have a chat window where each message is a TextBlock. I want to be able to select the text inside my TextBlocks. Google says to use a TextBox instead, which I cannot do because they do not support runs, which I am using to create hyperlinks inside my messages. What options do I have?
Check out the RichTextBox implementation for WPF.
How about making an CustomContentControl with TextBox (with selection style) and a Link in it and play with visibility based on content. Some thing like
<myControls:CustomContentControl>
<Grid>
// play with visibilty depending on content.
<CustomLink/>
<TextBox Style="{StaticResource SelectionStyle}"/>
</Grid>
</myControls:ContentControl>

List box in c# windows phone 7

Does list box allow placing a paragraph of word into it instead of a item one after another?
I think you just need to put a text block inside a scroll viewer, but this article shows how to make a control:
See this article
This is some code that does the basic work:
<ScrollViewer x:Name="MyScroller">
<TextBlock x:Name="MyTextBlock" TextWrapping="Wrap" Text="Some very long text here..." />
</ScrollViewer>
You'll see that if the area containing the text is bigger than the size of the textblock, you'll be able to scroll to view all text.

Categories