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:
The code, which is self-explanatory (I hope), is below:
#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([| |]) let cobj = ccons.Invoke([| |]) 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 [<EntryPoint>] [<System.STAThread>] let Main (args:string array) = (new Application()).Run(BuildApp())
<configuration> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <qualifyAssembly partialName="PresentationCore" fullName="PresentationCore,Version=22.214.171.124,Culture=neutral,PublicKeyToken=31bf3856ad364e35" /> <qualifyAssembly partialName="PresentationFramework" fullName="PresentationFramework,Version=126.96.36.199,Culture=neutral,PublicKeyToken=31bf3856ad364e35" /> </assemblyBinding> </runtime> </configuration>