Category Archives: User Interface

Working with XAML Designer 2 (UwpSurface)

In September 2017, Microsoft released a rewritten XAML Designer program within Visual Studio. It’s only enabled for a tiny fraction of apps and got a very quiet launch, so almost no one knows about it. The new version runs as UwpSurface.exe instead of XDesProc.exe and is only enabled for UWP apps targetting Fall Creators Update SDK or newer.
For my app, the new Designer simply broke everything initially. Why? Presumably for technical reasons, it only works with {Binding} and not {x:Bind} – but this was not made at all clear in the launch announcements. UWP developers have been encouraged to use {x:Bind}: it’s compiled, type-safe and faster, and x:Bind functions are the only way to do multibinding. For my 64-bit app, I never got design data or design instances working under XAML Designer (xdesproc), so I relied entirely upon {x:Bind}‘s FallbackValue parameter to preview different modes of my UI – but {Binding} has no equivalent mechanism.
After a lot of tinkering, I’ve finally learned a few important things about the new XAML Designer, and got a usable workflow.

Top Takeaways

  • UwpSurface is much faster and stabler than XDesProc. The dialog above (“Click here to reload the designer”) is largely history.
  • It works for both 32-bit and 64-bit apps (x86 or x64), which is a big step forward
  • Only {Binding} is evaluated; {x:Bind} is completely ignored.
  • DesignInstances (a live ViewModel) can be attached via DataContext or d:DataContext, although the DesignInstance parameter doesn’t seem to work
  • ViewModel code executes, but I don’t see any indication that View code executes, despite discussion to the contrary in Microsoft’s launch blog post
  • For C++/CX apps: due to a bug, only single-class ViewModels (without any C++/CX base classes) work as of Visual Studio 15.8.x. They’re fine in C#.
  • You can attach a debugger and see debug output from your ViewModel, or any exceptions. I haven’t been able to set breakpoints.

My strategy for a C++/CX app

  • Stick with {x:Bind} and its functions in most of my code
  • For the few properties that are central to a clean layout (usually about 2-5), use {Binding} and type converters
  • For those properties, build a duplicate “DesignTimeMock” ViewModel class – with no C++/CX base classes – and return the design-time property values there. Most properties can be safely omitted.
  • In the XAML code, define two different DataContexts like this:
    <UserControl.DataContext>
        <local:MyViewModel />
    </UserControl.DataContext>
    <d:UserControl.DataContext>
        <local:MyViewModel_DesignTimeMock/>
    </d:UserControl.DataContext>

    This attaches one ViewModel for runtime, and the mock for design time.

It’s not ideal. But… it’s better than nothing.

Closing Thoughts

Despite the difficulties, I do look forward to further improvements in the XAML Designer. The old version was dated and crash-prone, and a clean slate rewrite was the only reasonable path forward. It’s just going to take some time to reach feature parity with the old version, which will mean some teething pain for “guinea pig” developers like myself.

This One Weird Grid Trick in XAML

I recently found a neat XAML user interface trick that I hadn’t seen in my usual resources. Suppose you have:

  • a grid-based responsive user interface that you want to grow/shrink to fit the window
  • suppose it has a fixed width, and each row has a “core” minimum height it needs.
  • then there’s some extra vertical space that you want to sprinkle around
  • you have some priorities – first give row #1 extra space, then row #2 any extra.

XAML makes it easy to do proportional space allocation – e.g., give row #1 two-thirds and row #2 one-third by giving them “2*” and “*” height respectively. But it doesn’t do priorities.
The trick: combine a massive star size with a MaxHeight. That looks like this:

<Grid>
  <Grid.RowDefinitions>
    <RowDefinition Height="1000*" MaxHeight="200" />
    <RowDefinition Height="*" />
  </Grid.RowDefinitions>
</Grid>

Essentially, row #1 gets “first claim” on any extra space, up to a limit of 200 pixels. Any extra space beyond 200 pixels falls over to row #2.