Viewing Default WPF Control Templates (free tool)

For those of you that do not have Microsoft Expression Blend (or an equivalent), using XAMLPad and Visual Studio can be okay. However, if you want to create custom controls that are similar to existing (standard or third party) controls then it can be tricky to find out how best to do it. This little utility uses the XamlWriter class to export a default template from a WPF control.

I wanted to do this in F#, just to keep me using the language, although it is actually easier to code in C#. One benefit of using F# during development is that you can using the F# Interactive shell (FSI) which means you can also play with a wider range of cases directly. The following code was originally developed in FSI and does not really need any changes to work in FSI again. I’ve packaged it as an application so that it can run on machines without the Visual Studio and F# tools being installed. If you do use FSI, then make sure you execute the Application.Run(…) method as this creates the event loop which you will need for interaction with the controls. You will also need to Restart FSI any time that you throw an unhandled exception as you need to create a new AppDomain to host another Application instance.

You can download the application and code here:

To use the application, you need an assembly qualified type in the text box and then click the button. To make things easier, I have added shortened names for PresentationCore and PresentationFramework in the app.config file. Other assemblies will need to be named fully or else in the application folder. The code works for controls derived from System.Windows.Controls.Control as these have the Template property.

Here is a screenshot:

Screenshot

Screenshot

The code, which is self-explanatory (I hope), is below:

Program.fs

#light

(* Required assemblies:
  #r "System"
  #r "System.Core"
  #r "System.Xml"
  #r "PresentationCore"
  #r "PresentationFramework"
  #r "WindowsBase"
*)

open System.Windows
open System.Windows.Controls
open System.Windows.Markup
open System.Xml

module WPFControlTemplateViewer =

  let BuildApp () =

    // XML Writer Settings
    let xws = new XmlWriterSettings()
    do xws.Indent <- true
    do xws.IndentChars <- "  "
    do xws.NewLineOnAttributes <- false
    // Window construction
    let win = new Window()
    let sp = new DockPanel()
    let target = new TextBox()
    let btn = new Button()
    let tb = new TextBox()
    let spa = sp :> IAddChild
    let sp2 = new StackPanel()
    let bdr = new Border()
    let sv = new ScrollViewer()
    do sv.Content <- tb
    do sv.HorizontalScrollBarVisibility <- ScrollBarVisibility.Auto
    do sv.VerticalScrollBarVisibility <- ScrollBarVisibility.Auto
    do tb.Margin <- new Thickness(10.)
    do tb.IsReadOnly <- true
    do DockPanel.SetDock(target, Dock.Top)
    do DockPanel.SetDock(btn, Dock.Top)
    do DockPanel.SetDock(sp2, Dock.Top)
    do spa.AddChild(target)
    do spa.AddChild(btn)
    do spa.AddChild(sp2)
    do spa.AddChild(sv)
    do btn.Content <- "Get Template"
    do target.Text <- "System.Windows.Controls.TextBox,PresentationFramework"
    do win.Title <- "WPF Default Control Template Viewer"
    do win.Content <- sp
    // Click handler
    let f _ =
      let cname = target.Text
      try
        tb.Text <- ""
        let ct = System.Type.GetType(cname, true)
        let ccons = ct.GetConstructor(&#91;| |&#93;)
        let cobj = ccons.Invoke(&#91;| |&#93;)
        let cc = cobj :?> UIElement
        sp2.Children.Clear()
        let bdr = new Border()
        bdr.Padding <- new Thickness(10.)
        bdr.Child <- cc
        sp2.Children.Add(bdr) |> ignore
        if (cc :? System.Windows.Controls.Control) then
          let con = (cc :?> Control)
          let sw = new System.Text.StringBuilder()
          let xw = XmlWriter.Create(sw, xws)
          XamlWriter.Save(con.Template, xw)
          let tmplate = sw.ToString()
          (xw :> System.IDisposable).Dispose()
          tb.Text <- tmplate
          con.MinHeight <- 20.
        ()
      with (E : System.Exception) ->
        tb.Text <- E.ToString()
      ()
    do btn.Click.Add f
    win

  &#91;<EntryPoint>]
  [<System.STAThread>]
  let Main (args:string array) =
    (new Application()).Run(BuildApp())

app.config

<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<qualifyAssembly
partialName="PresentationCore"
fullName="PresentationCore,Version=3.0.0.0,Culture=neutral,PublicKeyToken=31bf3856ad364e35" />
<qualifyAssembly
partialName="PresentationFramework"
fullName="PresentationFramework,Version=3.0.0.0,Culture=neutral,PublicKeyToken=31bf3856ad364e35" />
</assemblyBinding>
</runtime>

</configuration>
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s