|
-
Feb 14th, 2009, 12:26 AM
#1
Thread Starter
Addicted Member
WPF RichTextBox Question
Recently I have decided to switch from the Forms RichTextBox to the WPF RichTextBox for my chat client. I've been reading up on applying properties to the text. I've found that I can use 2 methods to doing this.
Method 1:
Code:
TextRange tr = new TextRange(rtb.Document.ContentEnd, rtb.Document.ContentEnd);
tr.Text = "Some Text Here";
tr.ApplyPropertyValue(TextElement.ForegroundProperty, Brushes.Black);
Method 2:
Code:
Run r = new Run("Some Text Here");
r.FontFamily = new System.Windows.Media.FontFamily("Tahoma");
r.FontSize = 12;
r.FontStyle = System.Windows.FontStyles.Normal;
r.FontWeight = System.Windows.FontWeights.Regular;
r.Foreground = System.Windows.Media.Brushes.SteelBlue;
para.Inlines.Add(r);
At the moment I am using method 2. The server my client works uses a style-like tags around text to specify the color, font, weight, ect. So for each group of text in a style tag I create and add a new run object to the paragraph. My problem comes when I need to loop through the run to set hyperlinks and insert emoticons. Since all the text is not in a single run object I find that if a user uses a gradient (text fader) the style tags may open or close inside of a hyperlink or the emoticons text.
Eg. [style co:#D6D6D6]www.some[/style]site.com
"www.some" would be a run object and "site.com" would be another.
What I need to do is to figure how to either apply multiple properties to different segments of a run object or find a way to join multiple run objects. Unless there is some other way I have overlooked. I am still very new to WPF.
Here is a post with the method I use to add emoticons that shows how I loop through the run object.
Help with embedding images into a RichTextbox
-
Feb 14th, 2009, 09:14 AM
#2
Frenzied Member
Re: WPF RichTextBox Question
Your best bet is to pull all the content out into an array list or list of strings do the formatting their and then build a flow document (which is what the RTB uses) each time. That way your RUN's are re writen each time. Also rather than loop through the runs you could just apply some REGEX queries to replace each smilie code with the inline code for the given smilie. Im in work at the moment but I will post some code on how to do that later (around 7pm) for ya!
-
Feb 14th, 2009, 02:30 PM
#3
Frenzied Member
Re: WPF RichTextBox Question
Ok so I need to find out what exactly which way you are doing what your doing. So in your application do I type into a text box and then you update the RTB? Give me a run through and Il give you a hand?
-
Feb 14th, 2009, 06:48 PM
#4
Thread Starter
Addicted Member
Re: WPF RichTextBox Question
On self input yes. Say I type in "Hello! :P" and my font I have selected is Tahoma and the color is black it will pass the folowing string to be formatted to the rtb.
[style co:#000000;b;]Tewl : [/style][style ff:Tahoma;co:#000000]Hello! :P[/style]
-
Feb 15th, 2009, 06:09 AM
#5
Frenzied Member
Re: WPF RichTextBox Question
Ok sorry this took so long, I was playing with code. Now if you are using an RTB for your input box and another RTB for your "display" you do not need to use style tags or anything else for that matter. Consider that a flow document is simply a Xaml rendering control. This means that its content is all written in Xaml. Xaml is of course text. So if we use this nifty piece of code which is basically your method 1 extended:
Code:
Dim tr As New TextRange(PasteBox.Document.ContentStart, PasteBox.Document.ContentEnd)
Dim ms As New MemoryStream
tr.Save(ms, DataFormats.Xaml)
Dim TextArray As String = ASCIIEncoding.Default.GetString(ms.ToArray())
and text array now contains an array of your text with the Xaml mark-up included as a plain string. the content is already grouped with a section object from what I can gather from tests. So you would simply need to add this array as a section to your display window.
Now because you have the FULL power of flow documents you can now do something that most messengers cant do. you can make fantasticly rich content. so smilies embedded video, fancy lists! This all of course depends on your server construction but it is all technically possible. have fun with it!
-
Feb 15th, 2009, 12:51 PM
#6
Thread Starter
Addicted Member
Re: WPF RichTextBox Question
Last edited by Tewl; Feb 15th, 2009 at 12:58 PM.
-
Feb 15th, 2009, 01:45 PM
#7
Frenzied Member
Re: WPF RichTextBox Question
-
Feb 15th, 2009, 05:44 PM
#8
Thread Starter
Addicted Member
Re: WPF RichTextBox Question
I'm kinda of lost as to how to insert images and clickable urls with this method
-
Feb 15th, 2009, 06:25 PM
#9
Frenzied Member
Re: WPF RichTextBox Question
This is the flow document class. If you look towards the end you will see the different classes you can use with a flow document. The ones you need to look at is link and inline ui container.
-
Feb 16th, 2009, 04:00 PM
#10
Thread Starter
Addicted Member
Re: WPF RichTextBox Question
I was having an issue understanding the TextPointers but I think I have it now.
Code:
private void button1_Click(object sender, EventArgs e)
{
TextRange tr = new TextRange(rtb.Document.ContentStart, rtb.Document.ContentEnd);
TextPointer stp = rtb.Document.ContentStart.GetPositionAtOffset(tr.Text.Length - 2);
tr = new TextRange(rtb.Document.ContentEnd, rtb.Document.ContentEnd);
tr.Text = "\rSome :) text here";
tr.ApplyPropertyValue(TextElement.ForegroundProperty, System.Windows.Media.Brushes.Black);
tr = new TextRange(rtb.Document.ContentEnd, rtb.Document.ContentEnd);
tr.Text = "\rSome more text :) here";
tr.ApplyPropertyValue(TextElement.ForegroundProperty, System.Windows.Media.Brushes.Red);
tr = new TextRange(rtb.Document.ContentEnd, rtb.Document.ContentEnd);
tr.Text = "\rmore text here :)";
tr.ApplyPropertyValue(TextElement.ForegroundProperty, System.Windows.Media.Brushes.SteelBlue);
BitmapImage bi;
tr = new TextRange(stp, rtb.Document.ContentEnd);
string emoticonText = GetEmoticonText(tr.Text);
TextPointer tp = stp;
while (emoticonText != string.Empty)
{
while (!tp.GetTextInRun(LogicalDirection.Forward).StartsWith(emoticonText))
tp = tp.GetNextInsertionPosition(LogicalDirection.Forward);
tr = new TextRange(tp, tp.GetPositionAtOffset(emoticonText.Length));
tr.Text = string.Empty;
bi = new BitmapImage();
bi.BeginInit();
bi.UriSource = new Uri(mappings[emoticonText]);
bi.DecodePixelWidth = 26;
bi.EndInit();
System.Windows.Controls.Image image = new System.Windows.Controls.Image();
image.Width = 26;
image.Stretch = System.Windows.Media.Stretch.None;
image.Source = bi;
new InlineUIContainer(image, tp);
tr = new TextRange(tp, rtb.Document.ContentEnd);
if (tr.Text == string.Empty)
break;
else
emoticonText = GetEmoticonText(tr.Text);
}
}
private string GetEmoticonText(string text)
{
string match = string.Empty;
int lowestPosition = text.Length;
foreach (KeyValuePair<string, string> pair in mappings)
{
if (text.Contains(pair.Key))
{
int newPosition = text.IndexOf(pair.Key);
if (newPosition < lowestPosition)
{
match = pair.Key;
lowestPosition = newPosition;
}
}
}
return match;
}
I am curious as to why this returns a length of 2 when the RTB is empty.
TextRange tr = new TextRange(rtb.Document.ContentStart, rtb.Document.ContentEnd);
MessageBox.Show(tr.Text.Lengh.ToString());
Other than that, now all I have to do is write a function to convert urls tp clickable hyperlinks.
-
Feb 18th, 2009, 08:49 PM
#11
Thread Starter
Addicted Member
Re: WPF RichTextBox Question
Ok my next issue with this is putting in the Hyperlinks
Code:
string uriText = GetUriText(tr.Text);
Hyperlink h;
while (uriText != string.Empty)
{
while (!tp.GetTextInRun(LogicalDirection.Forward).StartsWith(uriText))
tp = tp.GetNextInsertionPosition(LogicalDirection.Forward);
h = new Hyperlink(tp, tp.GetPositionAtOffset(uriText.Length));
tp = tp.GetPositionAtOffset(uriText.Length);
tr = new TextRange(tp, rtb.Document.ContentEnd);
if (tr.Text != string.Empty)
uriText = GetUriText(tr.Text);
}
Code:
private string GetUriText(string text)
{
string match = string.Empty;
Regex r = new Regex("(?:^|[\\s\\[\\]\\}\\{\\(\\)\\\'\\\"<>])((?:(?:https?|gopher|ftp|file|irc):\\/\\/|www\\.)[a-zA-Z0-9\\.\\-=;&%\\?]+(?:\\/?[a-zA-Z0-9\\.\\-=;&%\\?]*)*)");
if (r.IsMatch(text))
{
Match m = r.Match(text);
match = m.Groups[1].Value;
}
return match;
}
After I run this I get a squiggly line under the url but it is not clickable nor does it fire any events when I add a click event to the hyperlink object.
-
Feb 18th, 2009, 08:57 PM
#12
Thread Starter
Addicted Member
Re: WPF RichTextBox Question
Screenshot: Removed bandwidth issue
Last edited by Tewl; Mar 4th, 2009 at 10:45 PM.
-
Feb 19th, 2009, 06:00 AM
#13
Frenzied Member
Re: WPF RichTextBox Question
Hmmmm, something is breaking your Links alright. You need to pull the xaml out and have a look to see if they are being created properly.
-
Feb 19th, 2009, 07:29 AM
#14
Thread Starter
Addicted Member
Re: WPF RichTextBox Question
hmmm. I'm kind of lost as to what to do at this point.
Code:
<Section xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xml:space="preserve" TextAlignment="Left" LineHeight="Auto" IsHyphenationEnabled="False" xml:lang="en-us" FlowDirection="LeftToRight" NumberSubstitution.CultureSource="User" NumberSubstitution.Substitution="AsCulture" FontFamily="Microsoft Sans Serif" FontStyle="Normal" FontWeight="Normal" FontStretch="Normal" FontSize="11" Foreground="#FF000000" Typography.StandardLigatures="True" Typography.ContextualLigatures="True" Typography.DiscretionaryLigatures="False" Typography.HistoricalLigatures="False" Typography.AnnotationAlternates="0" Typography.ContextualAlternates="True" Typography.HistoricalForms="False" Typography.Kerning="True" Typography.CapitalSpacing="False" Typography.CaseSensitiveForms="False" Typography.StylisticSet1="False" Typography.StylisticSet2="False" Typography.StylisticSet3="False" Typography.StylisticSet4="False" Typography.StylisticSet5="False" Typography.StylisticSet6="False" Typography.StylisticSet7="False" Typography.StylisticSet8="False" Typography.StylisticSet9="False" Typography.StylisticSet10="False" Typography.StylisticSet11="False" Typography.StylisticSet12="False" Typography.StylisticSet13="False" Typography.StylisticSet14="False" Typography.StylisticSet15="False" Typography.StylisticSet16="False" Typography.StylisticSet17="False" Typography.StylisticSet18="False" Typography.StylisticSet19="False" Typography.StylisticSet20="False" Typography.Fraction="Normal" Typography.SlashedZero="False" Typography.MathematicalGreek="False" Typography.EastAsianExpertForms="False" Typography.Variants="Normal" Typography.Capitals="Normal" Typography.NumeralStyle="Normal" Typography.NumeralAlignment="Normal" Typography.EastAsianWidths="Normal" Typography.EastAsianLanguage="Normal" Typography.StandardSwashes="0" Typography.ContextualSwashes="0" Typography.StylisticAlternates="0"><Paragraph><Run>
Some </Run><Run> </Run><Run> text here</Run><Run Foreground="#FFFF0000">
Some </Run><Hyperlink Foreground="#FF808080" TextDecorations="Underline"><Run Foreground="#FFFF0000">http://www.microsoft.com</Run></Hyperlink><Run Foreground="#FFFF0000"> more text </Run><Run> </Run><Run Foreground="#FFFF0000"> here</Run><Run Foreground="#FF4682B4">
more text here </Run><Run> </Run></Paragraph></Section>
Last edited by Tewl; Feb 20th, 2009 at 03:09 PM.
-
Feb 19th, 2009, 08:26 AM
#15
Frenzied Member
Re: WPF RichTextBox Question
I see the issue, your link doesnt have a navigateuri in it it only has text. see this http://msdn.microsoft.com/en-us/libr...hyperlink.aspx for usage.
-
Feb 19th, 2009, 08:56 AM
#16
Thread Starter
Addicted Member
Re: WPF RichTextBox Question
I get the same result if I set the NavigateUri as well
Code:
h = new Hyperlink(tp, tp.GetPositionAtOffset(uriText.Length));
h.NavigateUri = new Uri(uriText);
Code:
<Section xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xml:space="preserve" TextAlignment="Left" LineHeight="Auto" IsHyphenationEnabled="False" xml:lang="en-us" FlowDirection="LeftToRight" NumberSubstitution.CultureSource="User" NumberSubstitution.Substitution="AsCulture" FontFamily="Microsoft Sans Serif" FontStyle="Normal" FontWeight="Normal" FontStretch="Normal" FontSize="11" Foreground="#FF000000" Typography.StandardLigatures="True" Typography.ContextualLigatures="True" Typography.DiscretionaryLigatures="False" Typography.HistoricalLigatures="False" Typography.AnnotationAlternates="0" Typography.ContextualAlternates="True" Typography.HistoricalForms="False" Typography.Kerning="True" Typography.CapitalSpacing="False" Typography.CaseSensitiveForms="False" Typography.StylisticSet1="False" Typography.StylisticSet2="False" Typography.StylisticSet3="False" Typography.StylisticSet4="False" Typography.StylisticSet5="False" Typography.StylisticSet6="False" Typography.StylisticSet7="False" Typography.StylisticSet8="False" Typography.StylisticSet9="False" Typography.StylisticSet10="False" Typography.StylisticSet11="False" Typography.StylisticSet12="False" Typography.StylisticSet13="False" Typography.StylisticSet14="False" Typography.StylisticSet15="False" Typography.StylisticSet16="False" Typography.StylisticSet17="False" Typography.StylisticSet18="False" Typography.StylisticSet19="False" Typography.StylisticSet20="False" Typography.Fraction="Normal" Typography.SlashedZero="False" Typography.MathematicalGreek="False" Typography.EastAsianExpertForms="False" Typography.Variants="Normal" Typography.Capitals="Normal" Typography.NumeralStyle="Normal" Typography.NumeralAlignment="Normal" Typography.EastAsianWidths="Normal" Typography.EastAsianLanguage="Normal" Typography.StandardSwashes="0" Typography.ContextualSwashes="0" Typography.StylisticAlternates="0"><Paragraph><Run>
Some </Run><Run> </Run><Run> text here</Run><Run Foreground="#FFFF0000">
Some </Run><Hyperlink Foreground="#FF808080" NavigateUri="http://www.microsoft.com" TextDecorations="Underline"><Run Foreground="#FFFF0000">http://www.microsoft.com</Run></Hyperlink><Run Foreground="#FFFF0000"> more text </Run><Run> </Run><Run Foreground="#FFFF0000"> here</Run><Run Foreground="#FF4682B4">
more text here </Run><Run> </Run></Paragraph></Section>
-
Feb 19th, 2009, 04:43 PM
#17
Frenzied Member
Re: WPF RichTextBox Question
Try remove the runs manually and then put the xaml code back into the RTB via a section and see does it click then I think they are causing the issue.
-
Feb 20th, 2009, 03:57 AM
#18
Thread Starter
Addicted Member
Re: WPF RichTextBox Question
Doing that removes all of the formatting
-
Feb 20th, 2009, 07:46 AM
#19
Frenzied Member
Re: WPF RichTextBox Question
I know but for the moment we just need to find out if it is affecting the click ability of the link.
-
Feb 20th, 2009, 02:37 PM
#20
Thread Starter
Addicted Member
Re: WPF RichTextBox Question
Same result. Link is now grey. Updated screenshot above.
-
Feb 20th, 2009, 03:17 PM
#21
Frenzied Member
Re: WPF RichTextBox Question
and still not clickable. This may sound stupid but try to control click the link. Otherwise im out of ideas for the moment.
-
Feb 20th, 2009, 04:02 PM
#22
Thread Starter
Addicted Member
Re: WPF RichTextBox Question
I apparently the click event wouldnt fire. MouseLeftButtonDown however does. This fixes my main issue, now I just have to figure out how to insert the hyperlink to to text that is split into 2 seperate runs
<Run>http://www.micro</Run><Run>soft.com</Run>
Code:
tr = new TextRange(rtb.Document.ContentEnd, rtb.Document.ContentEnd);
tr.Text = "\rSome http://www.micro";
tr.ApplyPropertyValue(TextElement.ForegroundProperty, System.Windows.Media.Brushes.Red);
tr = new TextRange(rtb.Document.ContentEnd, rtb.Document.ContentEnd);
tr.Text = "soft.com more text :) here";
tr.ApplyPropertyValue(TextElement.ForegroundProperty, System.Windows.Media.Brushes.SteelBlue);
Last edited by Tewl; Mar 4th, 2009 at 10:46 PM.
-
Feb 22nd, 2009, 05:58 PM
#23
Frenzied Member
Re: WPF RichTextBox Question
One of your objects is not initialised. IE
MyVar VAR = new VAR;
-
Feb 23rd, 2009, 06:21 AM
#24
Thread Starter
Addicted Member
Re: WPF RichTextBox Question
It's the TextPointer that is null; it becomes null during the loop.
-
Feb 23rd, 2009, 07:37 AM
#25
Thread Starter
Addicted Member
Re: WPF RichTextBox Question
I was experimenting with a new method of inserting the text and managed to get this which works really well altho it doesn't fix my issue with inserting urls that are in 2 different Runs but that is a minor issue.
Code:
private void InsertHyperlink(TextPointer position)
{
string match = string.Empty;
Regex r = new Regex("(?:^|[\\s\\[\\]\\}\\{\\(\\)\\\'\\\"<>])((?:(?:https?|gopher|ftp|file|irc):\\/\\/|www\\.)[a-zA-Z0-9\\.\\-=;&%\\?]+(?:\\/?[a-zA-Z0-9\\.\\-=;&%\\?]*)*)");
Hyperlink h;
while (position != null)
{
if (position.CompareTo(this.Document.ContentEnd) == 0)
{
break;
}
if (position.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text)
{
String text = position.GetTextInRun(LogicalDirection.Forward);
Int32 indexInRun = -1;
if (r.IsMatch(text))
{
Match m = r.Match(text);
match = m.Groups[1].Value;
indexInRun = m.Groups[1].Index;
}
if (indexInRun >= 0)
{
position = position.GetPositionAtOffset(indexInRun);
h = new Hyperlink(position, position.GetPositionAtOffset(match.Length));
h.Tag = match;
h.Foreground = Brushes.Blue;
h.TextDecorations = TextDecorations.Underline;
h.Cursor = System.Windows.Input.Cursors.Hand;
h.MouseLeftButtonDown += new MouseButtonEventHandler(h_MouseLeftButtonDown);
position = position.GetPositionAtOffset(match.Length);
}
else
{
position = position.GetPositionAtOffset(text.Length);
}
}
else
{
position = position.GetNextContextPosition(LogicalDirection.Forward);
}
}
}
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|