tags:

views:

643

answers:

2

I have this XAML:

<TextBlock TextWrapping="Wrap" Foreground="Green"
           Text="This is some Green text up front. ">
    <TextBlock Foreground="Blue">
        This is some Blue text.
    </TextBlock>
    This is some Green text following the Blue text. 
    <Hyperlink>
        <TextBlock Text="And finally, this is a Hyperlink." TextWrapping="Wrap"/>
    </Hyperlink>
</TextBlock>

And I'd like to know how to replicate it procedurally in C#.

I know how to create TextBlocks in C# with something like:

TextBlock tb = new TextBlock();
tb.Text="Some text"

And I can put multiple textblocks together in a panel within C#. But I don't see how you go about putting TextBlocks into other TextBlocks, and TextBlocks into hyperlinks into Textblocks.

Are some container objects and extra TextBlock objects being created automatically, somehow? Or does the TextBlock have some methods/properties that allow it to contain the other items?

Other related questions:
1. What's the best way to add something like a Click() event to the Hyperlink?
2. Is there a way to get the blue text to wrap more cleanly? In the above XAML, as soon as the rightmost word would need to wrap, the entire block of blue text is wrapped instead.

Thanks for any illumination you can provide.

+1  A: 

I don't know about TextBlocks, but here is how you would do it in a RichTextBox. You could use a RichTextBox instead of a TextBlock.

 RichTextBox rtbTest = new RichTextBox();
 rtbTest.IsDocumentEnabled = true;

 FlowDocument fd = new FlowDocument();
 Paragraph para = new Paragraph();

 Run r4 = new Run("Some Text To Show As Hyperlink");
 Hyperlink h4 = new Hyperlink(r4);
 h4.Foreground = Brushes.Red; //whatever color you want the HyperLink to be

 // If you want the Hyperlink clickable
 h4.NavigateUri = new Uri("Some URL");
 h4.RequestNavigate += new RequestNavigateEventHandler(h_RequestNavigate);
 // Leaving the two previous lines out will still make the Hyperlink, but it won't be clickable

 // use this if you don't want an underline under the HyperLink
 h4.TextDecorations = null;

 para.Inlines.Add(h4);

 fd.Blocks.Add(para);

 rtbTest.Document = fd;

For normal text, I just used the HyperLink, but removed the two lines that made it clickable. This would give the text the color, but it wouldn't be clickable. Though it still makes the cursor change still. Though I am sure there is a property to change that also.

Eclipsed4utoo
+2  A: 

You can modify the collection of Inlines exposed via the TextBlock's Inlines property. The above XAML sample would look a little something like this:

TextBlock tb = new TextBlock
               {
                  Text = "This is some Green text up front.",
                  Foreground = Brushes.Green
               };

InlineCollection tbInlines = tb.Inlines;

tbInlines.Add(new Run
              {
                 Text = "This is some Blue text.",
                 TextWrapping = TextWrapping.Wrap,
                 Foreground = Brushes.Blue
              });

tbInlines.Add(new Run
              {
                 Text = "This is some Green text following the Blue text."
              });

Run hyperlinkRun = new Run("And finally, this is a Hyperlink.");

tbInlines.Add(new Hyperlink(hyperlinkRun));

As for your related questions:

1A) While it's possible to hook an event handler to every single Hyperlink instance using the RequestNavigate event on the class, that can be costly to setup and use more memory than is necessary. Instead I recommend leveraging routed events and simply hooking the RequestNavigate event at the container where all of your hyperlinks will be. You can do this like so:

myContainer.AddHandler(
                     Hyperlink.RequestNavigateEvent, 
                     new RequestNavigateEventHandler(
                                                      (sender, args) =>
                                                      {
                                                        /* sender is the instance of the Hyperlink that was clicked here */
                                                      }));

2A) In your XAML example it's treating the inner TextBlock as an element that needs to be wrapped all together. If you're using my Run based approach the wrapping should be inherited from the containing text block.

Drew Marsh
Thanks a lot. I was using a Dockpanel plus multiple TextBlocks, which had all sorts of wrapping issues. I switched to a Single TextBlock with multiple Runs and some added Hyperlinks, and it's wrapping beautifully. I was unabled to get the HyperLink.RequestNavigateEvent to trigger. I tried adding it at multiple locations from the Hyperlink itself, all the way up to the window with no luck. For now, Hyperlink.Click seems to be doing the trick. Any ideas?
IronFe56