Ok, once again I’m soliciting some audience participation as I’ve hit a dead end with a markup extension I’m working with in WPF.
I’m working on a localization markup extension that provides localized resource content using a simple markup extension with some additional features beyond what x:Static bindings provide. Specifically the ability to use a different resource manager, provide default values and the ability to use string based types for automatic type conversion. Yes, I know this has been done before and in fact my extension is based on some previous code found here from Christian Moser. I basically simplified this code and added a few additional features that I need for one of my projects.
The markup extension works great at runtime. It also works great in the designer as long as I host the extension class in the same project as the resources I binding against because I can easily find the ExecutingAssembly that I assume to hold application’s resources that will be used for binding.
The problem is that in order to create a ResourceManager I need to know which assembly the resources live in. A ResourceManager always requires an assembly reference (and resourceSet name) in its constructor to find the appropriate resources. Sounds easy enough, except I have been utterly stumped to find the Startup assembly (the WPF EXE) when running in the WPF designer.
The problem comes in when using the designer AND when trying to isolate the MarkupExtension into its own assembly/project. By moving the extension into another project I can no longer rely on Assembly.GetExecutingAssembly() to figure out the assembly where resources are coming from. Now at runtime it’s fairly easy to work around this by using Assembly.GetEntryAssembly() or even walking the control tree to find the main document and it’s underlying type and assembly.
However, in the WPF designer the actual Document is not walkable (all Parent refs are null), and GetEntryAssembly() throws an exception. Looking in the debugger while inside of the markup extension, reveals that the callstack goes straight presentation design time classes – the main WPF Exe doesn’t show up in the callstack (although the assembly IS loaded in the AppDomain.GetAssemblies()).
When running the designer too there’s no user code executing as far as I can tell, so even explicit type assignment in app.xaml.cs’s startup constructor doesn’t work.
I’m stumped. Right now the only way I can figure this out is to force the markup extension to run in the same assembly that contains the resources.
To give you an idea on what I’m doing, here’s a quick overview. The markup extension implements the required ProvideValue() method which delegates to ProvideValueInternal(). At the top of this method I try to retrieve the requested resource manager (which is caches internally) for the requested (or default) resource set.
/// Internal value retrieval
private object ProvideValueInternal()
// Get a cached resource manager for this resource set
ResourceManager resMan = this.GetResourceManager(this.ResourceSet);
object localized = null;
GetResourceManager() then tries to retrieve a cached resource manager or create a new one. And this where the problem starts:
/// Retrieves a resource manager for the appropriate ResourceSet
/// By default the 'global' Resource
/// <param name="resourceSet"></param>
private ResourceManager GetResourceManager(string resourceSet)
// At design time try to get the default assembly
if (ResExtension.Settings.DefaultResourceAssembly == null)
if ( string.IsNullOrEmpty(resourceSet) )
return DefaultResourceManager ?? null;
ResourceManager man = new ResourceManager(resourceSet, ResExtension.Settings.DefaultResourceAssembly);
The Settings object is static and holds all the ‘global’ configuration settings like the default assembly and default resource manager. The code basically checks whether the static Settings.DefaultResourceAssembly property is set and if it isn’t it will try to get it (once).
Currently this implementation is rigged to look at the current executing assembly:
/// This method tries to find the strongly typed Resource class in a project
/// so the designer works properly.
/// THIS CODE ASSUMES THE MAKKUP EXTENSION RUNS IN THE SAME ASSEMBLY THAT
/// ALSO CONTAINS RESOURCES. THIS IS DONE FOR THE DESIGNER ONLY. I HAVE
/// NOT BEEN ABLE TO FIGURE OUT A WAY TO GET A REFERENCE TO THE STARTUP
/// ASSEMBLY IN THE DESIGNER. IF YOU FIGURE OUT A WAY PLEASE CONTACT ME.
internal bool FindDefaultResourceAssembly()
// Assume the Document we're called is in the same assembly as resources
Assembly ass = Assembly.GetExecutingAssembly();
// Search for Properties.Resources in the Exported Types (has to be public!)
Type ResType = ass.GetExportedTypes().Where(type => type.FullName.Contains(".Properties.Resources")).FirstOrDefault();
if (ResType == null)
ResourceManager resMan = ResType.GetProperty("ResourceManager").GetValue(ResType, null) as ResourceManager;
this.DefaultResourceAssembly = ass;
this.DefaultResourceManager = resMan;
which works both at runtime and inside of the WPF designer as long as both the extension and the resources live in the same assembly.
The question is how to replace the GetExecutingAssembly call with something that will get me a reference to the main WPF EXE’s assembly. It works as is as long as I compile the markup extension into the same assembly as the resources. But otherwise no luck.
I’ve tried a bunch of different things here:
- Explicitly setting the Static Properties in Code
Doesn’t work because WPF doesn’t run any code. So app.xaml.cs doesn’t fire – there’s no global ‘entry point’ that
the designer runs AFAIK.
- Experimented around with GetCallingAssembly, GetExecutingAssembly, GetStartupAssembly
None of these worked as in the designer all but GetExecutingAssembly throw.
- Used Configuration Value to hold the assembly name
Didn’t work because WPF Designer doesn’t read AppSettings
- Tried walking the Control Tree up to the Document and grab type
Failed as in the WPF Designer all Parent references are null. No walking for you!
Anyway, I’m out of ideas so I’m throwing it out here.
Does anybody see a way to get at the default assembly in the WPF designer? Or am I approaching this in the wrong manner and there’s an easier way to assign the assembly generically?
If attached the extension’s .cs file in case anybody’s interested or wanting to experiment.
Other Posts you might also like