Display images in TextBlock (WPF)
Asked Answered
G

6

15

I'm working on a simple chat application. Currently the messages are binded to a custom-styled listbox like this (simplified XAML):

<ListBox ItemsSource="{Binding MessageCollection}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Text}"/>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Now I would like to be able to put images (like graphical smileys) into the displayed message text. Is there any way to achieve this using TextBlock (or any other standart component) or do I need to use some special control for this?

Thanks in advance

Glassco answered 7/4, 2009 at 19:26 Comment(0)
L
1

If you want the Images actually inside the text (like an emoticon), then you are going to have to do some work. This sounds like one of the few times I would actually want a User Control, the point of which would be one that scans the Text looking for emoticon values and building a Data Template on the fly.

Remember that anything you can do in XAML you can do in code, so the code I'm thinking of would follow this general idea:

  1. Scan text for emoticon values and create a list of values for data elements.
  2. Create a DockPanel.
  3. Foreach element in the List, add either a TextBlock or an Image (based on value).
  4. Set this.Content to the DockPanel.

I think something like this is actually what you are looking for, but if you want just an Image, then the ValueConverter suggestion would work.

Lechner answered 7/4, 2009 at 19:54 Comment(6)
I like this, sounds pretty simple. But I'm worried about the textwrapping ... I'll try to implement it and see how it works. Thanks.Glassco
That's a good point. You might need to do some measuring and break the text up as necessary to get the correct wrapping effect. It should only be an issue when an emoticon is present.Lechner
Anyway, I can't seem to find a way to do this. I've created custom user control but I don't know how to override the rendering mechanism and replace it with my code emitting TextBox/Image elements as required. Can you give me a hint please?Glassco
And since I need to do the measurements wouldn't it be easier to render both text and images myself? (By overriding the rendering method and using drawing tools)Glassco
Don't think of it as overriding the rendering mechanism: that's what we do in WinForms. Here, you will simply add elements to your DockPanel: DockPanel panel = new DockPanel(); panel.Add(new TextBlock("value")); panel.Add(new Image("source")); etc.Lechner
I haven't done any WPF by hand, so the above is psuedo code - you'll need to find the right property, etc. And all of this would probably be in a DataTemplate.Lechner
D
58

Just use the InlineUIContainer.

<TextBlock TextWrapping="Wrap">
    <Run>Some text.</Run>
    <InlineUIContainer>
        <Image Source="http://sstatic.net/stackoverflow/img/apple-touch-icon.png" Height="20"></Image>
    </InlineUIContainer>
    <Run>Some more text.</Run>
</TextBlock>
Dumbstruck answered 7/4, 2011 at 23:42 Comment(2)
How to make InlineUIContainer VerticalAlignment center?Believe
@JoeHuang BaselineAlignment = "Center"?Eviaevict
K
4

The Content of a TextBlock is always just a series of Inlines, so you should use the InlineUIContainer. You can insert this container as one of the Inlines in your TextBlock wherever you want an Image to appear, alternating with text Runs. You could parse a message and at the same time keep adding the tokens (either text or images) that you find to the Inlines collection of the TextBlock.

Kura answered 5/5, 2009 at 13:13 Comment(0)
T
1

You could use a value converter to convert the text to another type which has a list of segments which are composed of either text or the smiley face (in the order in which they appear).

Then, you can use a data template to bind to that new type and display the text and smiley faces appropriately.

Tit answered 7/4, 2009 at 19:34 Comment(1)
Could you please explain the second part a little more (or just link me to docs/sample). I think I understand the first part but don't know how to map two different data types to different elements.Glassco
L
1

If you want the Images actually inside the text (like an emoticon), then you are going to have to do some work. This sounds like one of the few times I would actually want a User Control, the point of which would be one that scans the Text looking for emoticon values and building a Data Template on the fly.

Remember that anything you can do in XAML you can do in code, so the code I'm thinking of would follow this general idea:

  1. Scan text for emoticon values and create a list of values for data elements.
  2. Create a DockPanel.
  3. Foreach element in the List, add either a TextBlock or an Image (based on value).
  4. Set this.Content to the DockPanel.

I think something like this is actually what you are looking for, but if you want just an Image, then the ValueConverter suggestion would work.

Lechner answered 7/4, 2009 at 19:54 Comment(6)
I like this, sounds pretty simple. But I'm worried about the textwrapping ... I'll try to implement it and see how it works. Thanks.Glassco
That's a good point. You might need to do some measuring and break the text up as necessary to get the correct wrapping effect. It should only be an issue when an emoticon is present.Lechner
Anyway, I can't seem to find a way to do this. I've created custom user control but I don't know how to override the rendering mechanism and replace it with my code emitting TextBox/Image elements as required. Can you give me a hint please?Glassco
And since I need to do the measurements wouldn't it be easier to render both text and images myself? (By overriding the rendering method and using drawing tools)Glassco
Don't think of it as overriding the rendering mechanism: that's what we do in WinForms. Here, you will simply add elements to your DockPanel: DockPanel panel = new DockPanel(); panel.Add(new TextBlock("value")); panel.Add(new Image("source")); etc.Lechner
I haven't done any WPF by hand, so the above is psuedo code - you'll need to find the right property, etc. And all of this would probably be in a DataTemplate.Lechner
L
1

I also encountered this problem recently and I overcome this by

Creating an ListBox ItemTemplate containing an ItemsControl that has a WrapPanel in the ItemsPanelTemplate and then binding my string to the ItemsSource of the ItemsControl with a IValueConverter that houses all the logic.

Split out your words and query/search your emoticons strings, hyperlinks etc and create your TextBlock, Image, Hyperlink, Button elements and set your values and event handles.

In the function create a List<UIElement> and populate the List with the controls you have generated and return the List as the object in the Convert function of the IValueConverter.

Because you have the WrapPanel in there you get your wrapping done.

Luttrell answered 12/4, 2012 at 15:49 Comment(0)
S
-1

Use the Image element instead of the TextBlock and use a Converter to map the text value to the smile image.

<ListBox ItemsSource="{Binding MessageCollection}">
<ListBox.ItemTemplate>
    <DataTemplate>
        <Image Source="{Binding Text, Converter={StaticResource MyImageConverter}}"/>
    </DataTemplate>
</ListBox.ItemTemplate>

Stereophonic answered 7/4, 2009 at 19:38 Comment(2)
But this will only allow an image in the message, right? What I want is combination of text and images in one message.Glassco
The DataTemplace can be everything you want. For Example <DataTemplate> <Grid> <TexBlock .../> <Image .../> <...other controls ...> </Grid> </DataTemplate>Stereophonic

© 2022 - 2024 — McMap. All rights reserved.