Hyperlink in WPF Richtextbox - wpf

I load WPF Richtextbox contents from Xaml string in which there are some Hyperlinks. When it is loaded into control, Hyperlinks are not clickable! I want to click on them and their associated URL shows up.

No freschx, it's about WPF. A WPF RichTextBox, unlike the one in WinForms, does not have a DetectUrls property. And it's weird you wrote a Xaml code for that, even weirder there is someone who thought it useful.
Check this post out where JHubbard80 and me had two different approaches to solve this problem.

To make the Hyperlink, or any inline UIElement in general, available for hit testing, we must set RichTextBox.IsDocumentEnabled to true.
To make the Hyperlink clickable without pressing the Ctrl key, the Hyperlink must be made read-only e.g., by wrapping it into a TextBlock or by making the complete RichTextBox read-only (by setting RichTextBox.IsReadOnly to false).
<RichTextBox IsDocumentEnabled="True">
<FlowDocument>
<Paragraph>
<Run Text="Some editable text" />
<TextBlock>
<Hyperlink NavigateUri="https://duckduckgo.com">
DuckDuckGo
</Hyperlink>
</TextBlock>
</Paragraph>
</FlowDocument>
</RichTextBox>

Ensure the DetectUrls property on the RichTextbox is set to true. You can then attach an event handler to the link clicked event and do what you wish.
<RichTextBox DetectUrls="True" />
Potential duplicate thread. Credit goes to Sam Meldrum from this thread.
For an even deeper analysis you may wish to try this article.

Related

Set size of InlineUIContainer?

I wrapped a TextBlock in an InlineUIContainer inside a RichTextBox, its content is bound to an external multi-line TextBox that the user updates on the spot.
What happens is the InlineUIContainer's size doesn't expand or shrink as needed, it's a static size, I need it to be extended according to the size of the inner TextBlock (I've tested the size of the TextBlock and it does resize according to its content).
Any way to do this? Of course a XAMLy way is preferred, even more verbose.
I don't know if it's a Silverlight thing, but trying out this in Kaxaml works (typing in the Textbox expands it):
<RichTextBox IsDocumentEnabled="true">
<FlowDocument>
<Paragraph>
<Run>cool </Run>
<InlineUIContainer><TextBox>woohoo</TextBox></InlineUIContainer>
<Run>stuff</Run>
</Paragraph>
</FlowDocument>
</RichTextBox>
I did an ugly and hacky workaround, hope to be able to replace it soon.
I made another property in the ViewModel, that returns:
string.IsNullOrWhitespace(comments) ?
string.Empty :
string.Format("Comments:{1}{0}{1}", comments, Environment.NewLine);
It works but is nasty.

TextBox Partially Editable

Is it possible to make the contents of a TextBox or a RichTextBox parially editable? For instance, I would like to have something that looks like the following:
<TextBox TextWrapping="Wrap" AcceptsReturn="True" VerticalScrollBarVisibility="Auto" FontFamily="Courier New" Margin="10,0">
This text and anything before it isn't editable.
This Text is Editable
This text and anything after it is not editable.
</TextBox>
or something like this:
<RichTextBox AcceptsReturn="True" VerticalScrollBarVisibility="Auto" FontFamily="Courier New" Margin="10,0">
<FlowDocument>
<Paragraph>This text and anything before it is not editable.</Paragraph>
<Paragraph>This text is editable.</Paragraph>
<Paragraph>This text and anything after it is not editable.</Paragraph>
</FlowDocument>
</RichTextBox>
Ideally, I would be able to style the editable text different than the uneditable text. Before anybody tells me I shouldn't do this, I have a valid reason for doing it.
Thanks in advance.
You should be able to encapsulate the three controls into a scrollable region and resize your editable field as needed (i.e., the editable field has no scrolling, only the containing region).
It's not very pretty, especially if there isn't an easy way of doing it with XAML (I've never used it, so I can't say), but I would content it's far better than trying to hack this thing into (Rich)TextBox.
A textBox with its Template overrriden to hide its border and 2 textblocks of same look and feel put ahead and post the textbox in that Template can achieve what you seek.
Default textbox template which you can override is here...

ContentControl render bug when using custom splash screen .Close() - what is going on?

I use a pretty basic ContentControl switching between different types of content:
<ContentControl Content="{Binding MyContent}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type local:Type1}">
<local:View1/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:Type2}">
<local:View2/>
</DataTemplate>
...
</ContentControl.Resources>
</ContentControl>
Randomly (like 20% of all runs), when a view is displayed, it displays completely transparent, but does not allow controls behind it to receive input.
If I try to use Snoop on the window, the view instantly renders. The view is even takes input and changes the mouse cursor when I hover over expected-to-be text boxes. If I press any button on the "invisible" view, it instantly pops up.
Switching from ContentControl to ContentPresenter did not change the above behavior.
Does anybody have a clue what is going on and how to fix it?
EDIT: It looks like a bug in WPF, so my best hope is somebody who have experienced this problem.
EDIT: I tracked it down to the custom splash screen window, being exact - to using .Close() to get rid of the window. If I use .Hide() instead, the glitch does not happen. Still not getting why.

WPF Binding Help

I haven't used WPF that much so the solution to this is probably pretty easy.
In the ide I'm developing it will have multiple controls(text editor) each being hosted in a tab, much like VS does for each source file. When the user clicks new the "host" creates a new EditorWindow(a usercontrol), creates a new tab, and tells the tab to display the EditorWindow it created, and then updates a property called currentWindow (of type EditorWindow) with the one that's currently active. Inside the EditorWindow is the text editor whose name is textEditor(also a property). What I'm trying to do is take this code from the quick start source of the text editor control I'm using
<StackPanel>
<CheckBox Checked="EditiorOptionsChecked" IsChecked="{Binding ElementName=Control, Path=currentWindow.textEditor.IsIndicatorMarginVisible}" Content="Indicator margin visible" />
<CheckBox Checked="EditiorOptionsChecked" IsChecked="{Binding ElementName=Control, Path=currentWindow.textEditor.IsLineNumberMarginVisible}" Content="Line number margin visible" />
<CheckBox Checked="EditiorOptionsChecked" IsChecked="{Binding ElementName=Control, Path=currentWindow.textEditor.IsRulerMarginVisible}" Content="Ruler margin visible (useful for fixed-width fonts only)" />
<CheckBox Checked="EditiorOptionsChecked" IsChecked="{Binding ElementName=Control, Path=currentWindow.textEditor.IsSelectionMarginVisible}" Content="Selection margin visible" />
</StackPanel>
put that in the host controls xaml, and bind the checkboxes to the syntax editor. I've tried a couple different things to no avail. Control is the name of the window hosting all the tabs, and path is obviously supposed to be the property that the checkboxes are bound too. I'm pretty sure the problem is that at initial run-time currentWindow isn't initialized so therefore my bindings aren't ever getting updated, but I'm at a loss as to how to fix this issue. Thanks!
Since you are new to WPF, you may not know that properties have to implement some sort of change notifications in order for bindings to work. For instance, if any of the properties in the the path "currentWindow.textEditor.IsIndicatorMarginVisible" change, you need to inform the binding engine that it has changed. If you implement these properties as DependencyPropertys, the change tracking comes for free. Otherwise, you should implement INotifyPropertyChanged.
I've found that the Snoop utility is the easiest way to do quick binding debugging, you should try using it and see if it tells you anything useful on the bound properties.

WPF: How to embed button inside text flow (wrap text around button)?

I'd like an advice to the following problem: I want to embed a Button into a text flow, but when I embed a Button and Label (or TextBlock) into the WrapPanel, I get the first figure:
alt text http://sklad.tomaskafka.com/files/wpf-wrappanel-problem.png
I think that one of solutions could be FlowDocument, but I feel that this is far too heavy for a control simple like this (which could be used in several hundred instances). Do you have some other ideas about how to implement this? Thank you!
EDIT:
One solution could be the following (I didn't know it was possible to put more stuff into TextBlock), but I would lose the ability to bind (which I need):
<TextBlock TextWrapping="Wrap">
<Span>
<Button x:Name="MyButton" Command="{Binding Path=MyCommand}" Content="+" />
<Run x:Name="MyLabel" Text="{Binding Path=Subject}" />
<!--
Problem: binding makes following error:
A 'Binding' cannot be set on the 'Text' property of type 'Run'.
A 'Binding' can only be set on a DependencyProperty of a DependencyObject.
-->
</Span>
</TextBlock>
To bind to Run.Text, checkout the BindableRun class by Fortes. Simple to implement, I use it all over my projects.
I found that implementing BindableRun correctly is pretty tricky - and almost all other available implementations will cause an exception from wpf layouting engine when the bound content changes from null to something non-null - see this problem, keyword "Collection was modified; enumeration operation may not execute."
Corrrect implementation from Microsoft is here - it shows how tricky this really is.
Solution: BindableRun class + the following markup:
<TextBlock>
<Button x:Name="MyButton" Command="{Binding Path=MyCommand}" Content="+" />
<common:BindableRun x:Name="Subject" BindableText="{Binding Path=Subject}"/>
</TextBlock>
Funny thing it works on the designer of a UserControl...
In that case, using the Property Change of your control to set the value to the Run is enough. I mean, if you had something like:
<TextBlock>
<Run Text="{Binding ElementName=thisCtrl, Path=Description}" />
</TextBlock>
Then just name the run, and on your property change handler of your UserControl DependencyProperty get/set the value.

Resources