Context
During the down time between software releases at work, we decided it was time to upgrade to Visual Studio 2013 (from 2012). I was hoping that using the newer version would solve a XAML designer issue we encountered on occasion with VS 2012 where certain WPF user controls generated an “Invalid Markup” message. My hopes were dashed:
The confusing thing is that everything compiles (no errors, no warnings), and the application runs beautifully.
Let’s Start Digging
This seemed to be happening on several views, so I picked one and looked more closely at the compiler errors that only appear when viewing the XAML.
According to the MSDN documentation for the CacheMode
property, everything was in order. On a whim I tried using the property element syntax:
<Border Grid.Column="3" Grid.RowSpan="2" BorderBrush="#FF999999" BorderThickness="1" Background="{DynamicResource Fill_SidePanelBackground}" Margin="0,0,0,0"> <Border.CacheMode><BitmapCache /></Border.CacheMode> </Border>
Errors Gone, But Now There Are Warnings
Now the compiler is giving me warnings about not being able to find dynamic resources (e.g., brushes).
After verifying that those keys do indeed exist in resource dictionaries, and that those resources work exactly as expected at runtime, I was getting confused.
Some investigation on Stack Overflow yielded something of interest. One of the posts involved using dynamically loaded modules; in other words, the application is put together at runtime rather than everything being known at compile-time. That’s nearly identical to what our application does: We use Prism to keep our modules separate, allowing them to have their own dependencies that are resolved at runtime.
The Potential Problem
The XAML views that exhibited this behavior are typically custom controls that reference application-wide styles via merged resource dictionaries.
All of the styles, brushes, etc. are bound together in App.xaml:
<Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="pack://application:,,,/Daxor.Lab.ResourceDictionaries;component/ResourceDictionaries/Common/ImageBitmaps.xaml"/> <ResourceDictionary Source="pack://application:,,,/Daxor.Lab.ResourceDictionaries;component/ResourceDictionaries/Common/VectorGraphics.xaml"/> <ResourceDictionary Source="pack://application:,,,/Daxor.Lab.ResourceDictionaries;component/ResourceDictionaries/Common/Converters.xaml"/> <ResourceDictionary Source="pack://application:,,,/Daxor.Lab.ResourceDictionaries;component/Themes/DefaultTheme.xaml"/> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources>
Our application has a domain-driven design architecture so that each module is a bounded context, and thereby responsible for its own dependencies. The aforementioned use of Prism allows us to have individual modules with their own user controls, which reference application-level resources.
However, the Visual Studio XAML designer has no clue to what Application those controls belong at design time.
A Solution
The problem is that the designer doesn’t know where to find the brushes. If only it knew about those resources!
All of the XAML-related resources live in their own assembly, so I tried adding that assembly as a reference for the module in question.
Referencing the resource dictionaries in the user control itself allowed the designer to be happy once again (i.e., no errors, no warnings, and properly rendered XAML in the designer).
<UserControl.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="pack://application:,,,/Daxor.Lab.ResourceDictionaries;component/Themes/DefaultTheme.xaml"/> </ResourceDictionary.MergedDictionaries>
Why I’m Okay with This
For domain-driven design (DDD) there is typically some kind of infrastructure you rely upon to interact with specific tech. In our case the tech is WPF.
As long as that infrastructure is in a separate assembly (i.e., a separate dependency), we haven’t really violated any of the DDD principles — at least I don’t think we have.
The downside is that each view that has these issues now has to reference another assembly and have dictionary merging put into the XAML.
Conclusion
This isn’t the cleanest solution. However, the XAML renders properly in Visual Studio, thus making the tool usable.
Without the visual designer for XAML, it’s very difficult to determine how XAML changes impact the UI. I can parse XAML with the best of them, but I’d rather have a tool do that for me.
If you have some ideas of other solutions, I’d be happy to hear them! Please leave a comment below.