Channels ▼
RSS

.NET

Embed Custom GUIs in WPF

Source Code Accompanies This Article. Download It Now.


Clipboard Operations

Go back to the WPF Compound Documents sample application and insert some PhotoControls and TimeStampControls. Select content that includes these controls, right-click the selection, and select Copy. Then verify that the copied content can be pasted. The sample app is able to copy, cut, and paste UserControls by following this procedure when content is copied (see DocumentWindow.Copy). Before copying, the Name attributes of all UserControls in the selected content are extracted by a call to GetUserControlNames (Listing Two). Then PlaceholderControls are inserted into the empty BlockUIContainers and InlineUIContainers. The inserted PlaceholderControls have the same Name attribute value as the original UserControls. This modified XAML, containing the PlaceholderControls, is copied to the clipboard. Later, when users perfom a paste, the pasted PlaceholderControls is replaced with the original UserControls.


// Get control names of all UserControls in the specified document 
// region.
public static List<string> GetUserControlNames(TextPointer start, 
                                               TextPointer end)
{
  List<string> userControlNames = new List<string>();
  TextPointer current = start;
  // Scan through the document fragment...
  while (current.CompareTo(end) < 0)
  {
    // If we encounter something that could potentially
    // contain a UserControl...
    if (current.Parent is BlockUIContainer || 
        current.Parent is InlineUIContainer)
    {
      // Get the BlockUIContainer or InlilneUIContainer's  full 
      // XAML markup.
      string containerMarkup = XamlWriter.Save(current.Parent);
      XmlDocument xmlDocument = new XmlDocument();
      xmlDocument.LoadXml(containerMarkup);

      // Extract the Name attribute from the XAML markup.
      XmlAttribute nameAttribute = 
        xmlDocument.DocumentElement.FirstChild.Attributes["Name"];
      string name = null;
      if (nameAttribute != null && 
          !string.IsNullOrEmpty(nameAttribute.Value))
      {
        name = nameAttribute.Value;
      }
      else
      {
        Debug.Assert(false);
      }
      // Store the UserControl's name in the List, avoiding 
      // duplicates.
      if (!userControlNames.Contains(name))
      {
        userControlNames.Add(name);
      }
    }
    current = 
        current.GetNextContextPosition(LogicalDirection.Forward);
  }
  return userControlNames;
}
Listing Two

IEnhancedUserControl

A UserControl usually has state that must be saved before converting it into a PlaceholderControl. The same state has to be loaded when PlaceholderControl is replaced by the original UserControl. For example, when a PhotoControl is converted to a Placeholder control, the image files selected by users must be saved, along with the Slideshow checkbox state, the width and height, and the number of seconds. That's why the PhotoControl and TimeStampControl classes implement the IEnhancedUserControl interface:


public interface IEnhancedUserControl
{
  void Save(IEnhancedUserControl      enhancedUserControl,
          string name, ICloneable              dataToPersist);
  void Load(ICloneable dataToPersist);
  string GetPrintMarkup();
  string Name { get; set; }
}


Because the sample app's UserControls all implement this interface, the program can save each UserControl's state, and restore it whenever necessary. To see the IEnhancedUserControl interface at work, take a look at EnhancedUserControlUtils.ReplacePlaceholdersWithRealControls (Listing One). Once it has found a PlaceholderControl, it calls the ControlFactory to create the real UserControl. It assigns a unique Name value to this control. Then it loads the control with data that was previously saved by calling the UserControl's Load method. Before the data is loaded into the UserControl, it is cloned. This prevents one UserControl from modifying another UserControl's data.

When the document is printed, the print code calls IEnhancedUserControl.GetPrintMarkup() and renders the XAML returned by that method. This lets a UserControl have a totally different appearance when printed. For example, when the PhotoControl is printed, none of the buttons or checkboxes are displayed. Only the selected image appears on the printed page. The print files, DocumentPaginatorWrapper.cs and Print.cs, are based on code posted in Feng Yuan's blog (see the source code for the URL).

It's easy to add your own custom UserControls. Just make sure your UserControl implements the IEnhancedUserControl interface. Also, add your control to EnhancedUserControlUtils.ControlFactory and EnhancedUserControlUtils.ControlTypeNames.

As of WPF 3.5, the support for embedded GUIs in FlowDocuments is incomplete. This situation will likely improve in subsequent versions of .NET. In the meantime, you can use the techniques in this article to create full-fledged interactive GUIs that can be embedded in FlowDocuments.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video