InlineUIContainer
RadRichTextBox provides you with the functionality of enclosing custom UI elements in its document. This is achieved with the help of a special type of inline document element called InlineUIContainer, which can wrap any object of type System.Windows.UIElement, e.g. a button, an image or even a media element or media player.
The InlineUIContainer is an inline element, so it should be placed in a Block that can contain inline elements (e.g. Paragraph).
Add UI Element to an InlineUIContainer
You can add any element that derives from the UIElement class inside the InlineUIContainer. To do that, simply wrap the desired element inside the tag of the InlineUIContainer in case you are defining it in XAML. If you are using code, use the UIElement property of the container. Here is a simple example with a Button.
In order to utilize the InlineUIContainer, you have to set its Height and Width explicitly (or use the constructor that takes a Size as a parameter). Otherwise, they will not be shown in the document.
Example 1: Add UI Element to an InlineUIContainer
<telerik:RadRichTextBox Name="radRichTextBox">
<telerik:RadDocument>
<telerik:Section>
<telerik:Paragraph>
<telerik:InlineUIContainer Height="25" Width="70">
<Button Name="button" Content="Button" />
</telerik:InlineUIContainer>
</telerik:Paragraph>
</telerik:Section>
</telerik:RadDocument>
</telerik:RadRichTextBox>
Example 1: Add UI Element to an InlineUIContainer
Section section = new Section();
Paragraph paragraph = new Paragraph();
InlineUIContainer container = new InlineUIContainer();
container.UiElement = new Button();
container.Height = 25;
container.Width = 70;
paragraph.Inlines.Add(container);
section.Blocks.Add(paragraph);
this.radRichTextBox.Document.Sections.Add(section);
Dim _section As New Section()
Dim _paragraph As New Paragraph()
Dim container As New InlineUIContainer()
container.UiElement = New Button()
container.Height = 25
container.Width = 70
_paragraph.Inlines.Add(container)
_section.Blocks.Add(_paragraph)
Me.radRichTextBox.Document.Sections.Add(_section)
Example 2 is a more complex example, which demonstrates how to implement a Button that inserts a MediaElement inside the RadRichTextBox's document.
Example 2: Add MediaElement on Button Click
private static Size defaultSize = new Size(900, 400);
private void InsertMedia(Size size)
{
OpenFileDialog ofd = new OpenFileDialog();
if (ofd.ShowDialog() == true)
{
Stream stream = ofd.File.OpenRead();
MediaElement media = new MediaElement();
media.SetSource(stream);
media.AutoPlay = true;
InlineUIContainer container = new InlineUIContainer()
{
UiElement = media
};
if (size != Size.Empty)
{
container.Height = size.Height;
container.Width = size.Width;
}
this.radRichTextBox1.InsertInline(container);
}
}
private void buttonInsertVideo_Click(object sender, RoutedEventArgs e)
{
InsertMedia(defaultSize);
}
private void buttonInsertAudio_Click(object sender, RoutedEventArgs e)
{
InsertMedia(Size.Empty);
}
Private Shared defaultSize As New Size(900, 400)
Private Sub InsertMedia(ByVal _size As Size)
Dim ofd As New OpenFileDialog()
If ofd.ShowDialog() = True Then
Dim _stream As Stream = ofd.File.OpenRead()
Dim media As New MediaElement()
media.SetSource(_stream)
media.AutoPlay = True
Dim container As New InlineUIContainer() With {.UiElement = media}
If _size <> Size.Empty Then
container.Height = _size.Height
container.Width = _size.Width
End If
Me.radRichTextBox1.InsertInline(container)
End If
End Sub
Private Sub buttonInsertVideo_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
InsertMedia(defaultSize)
End Sub
Private Sub buttonInsertAudio_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
InsertMedia(Size.Empty)
End Sub
Specifics
InlineUIContainer elements are not copyable.
The following scenarios are affected:
- Drag-and-drop operation
- Copy/paste operation
- Update of the layout when the InlineUIContainer is in the header/footer
- Print operation
The reason is that copying InlineUIContainer involves cloning of the internal UIElement, which cannot be handled in a generic way.
To enable copying of InlineUIContainers in your application, you can create a custom object, which can copy the UIElement inside the container. What you need to do is to inherit the InlineUIContainer class and override IsCopyable, CreateNewElementInstance(), CopyPropertiesFromOverride(). The container and its parts are copied in the CopyPropertiesFromOverride() method, so you should ensure that the override copies the UIElement inside the container as well.
Example 3: Implement CopyableInlineUIContainer for a Button as underlying UIElement
public class CopyableInlineUIContainer : InlineUIContainer
{
internal CopyableInlineUIContainer()
{
}
public CopyableInlineUIContainer(UIElement uiElement, Size size)
: base(uiElement, size)
{
}
public override bool IsCopyable
{
get
{
return true;
}
}
protected override DocumentElement CreateNewElementInstance()
{
return new CopyableInlineUIContainer();
}
protected override void CopyPropertiesFromOverride(DocumentElement fromElement)
{
CopyableInlineUIContainer fromUIContainer = (CopyableInlineUIContainer) fromElement;
this.Width = fromUIContainer.Width;
this.Height = fromUIContainer.Height;
Button originalButton = (Button) fromUIContainer.UiElement;
this.UiElement = new Button()
{
Width = originalButton.Width,
Height = originalButton.Height,
Content = originalButton.Content.ToString()
};
}
}
Public Class CopyableInlineUIContainer
Inherits InlineUIContainer
Friend Sub New()
End Sub
Public Sub New(ByVal uiElement As UIElement, ByVal size As Size)
MyBase.New(uiElement, size)
End Sub
Public Overrides ReadOnly Property IsCopyable As Boolean
Get
Return True
End Get
End Property
Protected Overrides Function CreateNewElementInstance() As DocumentElement
Return New CopyableInlineUIContainer()
End Function
Protected Overrides Sub CopyPropertiesFromOverride(ByVal fromElement As DocumentElement)
Dim fromUIContainer As CopyableInlineUIContainer = CType(fromElement, CopyableInlineUIContainer)
Me.Width = fromUIContainer.Width
Me.Height = fromUIContainer.Height
Dim originalButton As Button = CType(fromUIContainer.UiElement, Button)
Me.UiElement = New Button() With {
.Width = originalButton.Width,
.Height = originalButton.Height,
.Content = originalButton.Content.ToString()
}
End Sub
End Class
There is a very generic option for copying UIElement objects, which might help in most of the cases. However, have in mind that depending on the UI elements on which it will be invoked, the implementation might differ.
Example 4: Copy UI Element
public static UIElement Clone(this UIElement elementToClone)
{
if (elementToClone != null)
{
string elementXaml = XamlWriter.Save(elementToClone);
StringReader stringReader = new StringReader(elementXaml);
XmlReader xmlReader = XmlTextReader.Create(stringReader, new XmlReaderSettings());
return (UIElement)XamlReader.Load(xmlReader);
}
return null;
}
<Extension()>
Public Shared Function Clone(ByVal elementToClone As UIElement) As UIElement
If elementToClone IsNot Nothing Then
Dim elementXaml As String = XamlWriter.Save(elementToClone)
Dim stringReader As StringReader = New StringReader(elementXaml)
Dim xmlReader As XmlReader = XmlTextReader.Create(stringReader, New XmlReaderSettings())
Return CType(XamlReader.Load(xmlReader), UIElement)
End If
Return Nothing
End Function
Import/Export InlineUIContainers
Most features that RadRichTextBox provides are also supported in the format providers that it uses for export and import.
For more information on Import/Export, please refer to this topic.
However, as the UIElement class is a WPF specific concept, some format providers support them in a non-standard way and others do not support them at all.
Exporting InlineUIContainers:
Different approaches have been adopted when it comes to exporting inline UI containers via the format providers:
XamlFormatProvider: Inline UI containers are serialized as expected, thus ensuring lossless export in simple cases, e.g. when a button is in the container. Custom attached properties may not be exported.
HtmlFormatProvider: The inline UI containers are serialized as XAML and are included in the HTML as comments. If the user handles the InlineUIContainerExporting event, they can provide their own implementation for the export of the UI elements by accessing the properties of the InlineUIContainerExportingEventArgs and setting the ones they need. The CommentContent contains the XAML serialization and the HtmlContent string property can be set to the desired user-defined HTML equivalent of the UI element. It will appear when the page is rendered outside RadRichTextBox. The UI element can also be omitted from the document altogether.
DocxFormatProvider: All InlineUIContainers are ignored as the Microsoft Word concept of controls is quite different.
RtfFormatProvider: All InlineUIContainers are ignored as the RTF standard does not have a concept for similar elements.
PdfFormatProvider: The InlineUIContainers are taken a snapshot of and included in the export. If you like, you can prevent that by setting the InlineUIContainersExportMode property of the provider to None.
Importing InlineUIContainers
There are some differences between the format providers when it comes to importing InlineUIContainers, too.
XamlFormatProvider: All inline UI containers are deserialized and imported.
DocxFormatProvider: There cannot be any inline UI containers in DOCX, as they are not exported in the first place.
RtfFormatProvider: There cannot be any inline UI containers in RTF, as they are not exported in the first place.
PdfFormatProvider: PDF import is currently not supported.