Practical .NET

Construct XAML Forms at Runtime with Resource Files

WPF makes it very easy to load non-executable resources at run time -- including a complete UI in XAML. Here's how to leverage that functionality to create applications that you can customize without recompiling.

Sometimes different users need different UIs, or different sites where your application is installed need different UIs. You could add a bunch of logic that makes controls visible or invisible as needed (and best of luck testing that). Or you could just load the UI that your user or site needs. In that scenario, the ultimate form contains no content:

<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">

</Window>

At runtime, you'll now need to load the UI based on settings in a config file or the preferences of the currently logged on user. To support that, you can define each of those UIs in your XAML file, then paste each of them into a separate XML file. This example, in a file called MyGrid.xml, defines a Grid containing a DataGrid and two buttons:

<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <DataGrid Name="DataGrid1" … />
    <Button Name="UpdateBtn" … />
    <Button Content="DeleteBtn" … />
  </Grid>

By default, any XML file you add to your project is a resource file; and when your file absolutely, positively has to be present, a resource file is your best choice. A resource file is compiled into your executable and guaranteed to be distributed with it. If you have a limited number of configurations, you can set them up as individual resource files and compile them all into your executable.

However, if you don't want the file to be incorporated into your executable, you should select the XML file in Solution Explorer and set its Build Action property to Content. A content file won't be distributed with your application (at least if you use any of the standard distribution methods). Instead, it will be a separate file you must copy to the folder holding your executable, but can then replace or modify at your convenience.

To ensure that the file is copied to the folder with your executable (this makes referring to the resource in your code easier), set the file's Copy To Output Directory property. To ensure you get the most recent version of the file, set the file's Copy To Output Directory to Copy If Newer.

Accessing a Resource File
Now you're ready to write the code to load the UI appropriate for your user or installation. First you need to create a StreamResourceInfo class, passing the URI for your resource file. Next, create a XamlReader to pull the XAML from the file.

You can then call the XamlReader's LoadAsync method, passing the Stream property of your StreamResoureInfo object. You'll need to cast the output of the LoadAsync method to the kind of resource you're pulling from the file. For this example, since the file contains a Grid, the output must be cast as a Grid. This code in the form's Window Loaded event does the trick for a resource file:

Dim GridUri As New Uri("/MyGrid.xml", UriKind.Relative)
Dim sri As Windows.Resources.StreamResourceInfo =
         Application.GetResourceStream(GridUri)
Dim xrdr As New System.Windows.Markup.XamlReader()
Dim grd As Grid = CType(xrdr.LoadAsync(sri.Stream), Grid)
Me.Content = grd

The code is only slightly different if you've used a Content file: Instead of using the Application's GetResourceStream method, use its GetContentStream method.

Of course, you'll want to gain access to the controls you've just loaded. Since this code has a variable pointing to the Grid that holds the controls, you can use the Grid's Children collection to access each of the controls the Grid holds. This code accesses the second control (a button) and wires up an event handler for its Click event:

Dim UpdBtn As Button
  UpdBtn = CType(grd.Children(1), Button)
  AddHandler UpdBtn.Click, AddressOf DoUpdate

After deploying your application, you'll be able to modify or replace to update or customize your application -- if you've set your XML files up as a content file. While replacing your whole UI is an extreme example, you could just as easily use this technique with the Content property of a Frame that defines part of your page. Either way, you can eliminate a bunch of control logic that modifies your UI with a half-dozen lines of code that just reads in the right UI.

About the Author

Peter Vogel is a system architect and principal in PH&V Information Services. PH&V provides full-stack consulting from UX design through object modeling to database design. Peter tweets about his VSM columns with the hashtag #vogelarticles. His blog posts on user experience design can be found at http://blog.learningtree.com/tag/ui/.

comments powered by Disqus

Featured

  • Microsoft Revamps Fledgling AutoGen Framework for Agentic AI

    Only at v0.4, Microsoft's AutoGen framework for agentic AI -- the hottest new trend in AI development -- has already undergone a complete revamp, going to an asynchronous, event-driven architecture.

  • IDE Irony: Coding Errors Cause 'Critical' Vulnerability in Visual Studio

    In a larger-than-normal Patch Tuesday, Microsoft warned of a "critical" vulnerability in Visual Studio that should be fixed immediately if automatic patching isn't enabled, ironically caused by coding errors.

  • Building Blazor Applications

    A trio of Blazor experts will conduct a full-day workshop for devs to learn everything about the tech a a March developer conference in Las Vegas keynoted by Microsoft execs and featuring many Microsoft devs.

  • Gradient Boosting Regression Using C#

    Dr. James McCaffrey from Microsoft Research presents a complete end-to-end demonstration of the gradient boosting regression technique, where the goal is to predict a single numeric value. Compared to existing library implementations of gradient boosting regression, a from-scratch implementation allows much easier customization and integration with other .NET systems.

  • Microsoft Execs to Tackle AI and Cloud in Dev Conference Keynotes

    AI unsurprisingly is all over keynotes that Microsoft execs will helm to kick off the Visual Studio Live! developer conference in Las Vegas, March 10-14, which the company described as "a must-attend event."

Subscribe on YouTube