A Tour of XAML VIII: More fun with Markup Compatibility
In a previous post about markup compatibility I described how it can be used
to enable
forward compatibility in XAML documents; documents that take advantage of
features in, say, a 2.0 version of the document format but can also be viewed
when only the 1.0 version is available. Using a technique similar
the previous XAML post, we can also use AlternateContent
to get the effect of conditional compilation.
Let say you want to have a label in a dialog that indicates that this is beta
software so your customers will not confuse it with your production version. One
way to accomplish this is to conditionally compile an
XmlnsDefinition attribute into an assembly referenced by the project. When the conditional symbol is defined, the WPF XAML
compiler will consider the namespace defined by the
XmlnsDefinition attribute as known. If the conditional is not defined,
the assembly will not have the XmlnsDefinition
attribute and the namespace will be considered unknown. This can be done by
adding the following code to a referenced assembly,
Remember, this must be an assembly referenced by the project, not in the
project itself (I explain why below).
You can then conditionally include a label, as in,
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">
xmlns:beta="BetaVersion"
...
<mc:AlternateContent>
<mc:Choice Requires="beta">
<Label>
This is BETA software. Do not distribute.
Use at your own risk.
<Label>
</mc:Choice>
<mc:AlternateContent>
...
<:/Window>
The label will only be included in the beta version of the assembly, not the
production version (assuming that BETA is not defined for the production
version, a mistake I have made before...). You can even make it more complicated
by having other dummy namespaces for other versions and a fallback to catch when
the build configuration was not correctly set up, such as,
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">
xmlns:alpha="AlphaVersion"
xmlns:beta="BetaVersion"
xmlns:production="ProductionVersion"
...
<mc:AlternateContent>
<mc:Choice Requires="alpha">
<Label>
This is ALPHA software. Confidential.
Internal use only. Do not distribute
<Label>
</mc:Choice>
<mc:Choice Requires="beta">
<Label>
This is BETA software. Do not distribute.
Use at your own risk.
<Label>
</mc:Choice>
<mc:Choice Requires="production">
</mc:Choice>
<mc:Fallback>
<Label>
Franken-build, beware! For test purposes only.
Confidential. Internal use only.
Do not distribute.
The official build script was not used to
produce this assembly.
</Label>
</mc:Fallback>
<mc:AlternateContent>
...
</Window>
I believe this technique is superior to other techniques I have seen
described involving data binding and/or triggers because the resulting
production version has no runtime overhead for the beta label. The production
choice doesn't mention the label at all; the BAML file will not contain any
reference to the label and no label will be created at runtime. It is equivalent
deleting the entire alternate content block. Also, since it only uses XAML
features, not WPF features, it is usable in non-WPF dialects.
If you adopt this technique, I recommend adding the dummy namespaces to an assembly that contains only XmlnsDefinition
attributes. Since this assembly doesn't contain any code, the C# compiler will
not include it among the references in the final assembly therefore you don't
have to distribute it.
The reason you cannot include the XmlnsDefinition
in the project itself is because the XAML is compiled before the assembly is built
(most of the time, I will get into the details of this in a later post). The
compiler cannot know what attributes are in the project until the project's
assembly has been built. Since the BAML file needs to be in included in the
assembly, it must be compiled before the assembly. This is a catch-22 so the compiler ignores
XmlnsDefintiion attributes in the project assembly but
will respect attributes in referenced assemblies (which are built before the XAML
is compiled).
In a future version of XAML we might consider adding formal support for
conditional compilation but, for now, you can get the effect of conditional
compilation through the use of AlternateContent, even
if it is a bit indirect.
Hello! I tried this example with a bit more complex structure Window>StackPanel and immediately get error, something like "cannot convert ListBox to ListBoxItem" (they were inside a conditional tag). Can you check it, please?
A Tour of XAML VIII: More fun with Markup Compatibility
In a previous post about markup compatibility I described how it can be used to enable forward compatibility in XAML documents; documents that take advantage of features in, say, a 2.0 version of the document format but can also be viewed when only the 1.0 version is available. Using a technique similar the previous XAML post, we can also use AlternateContent to get the effect of conditional compilation.
Let say you want to have a label in a dialog that indicates that this is beta software so your customers will not confuse it with your production version. One way to accomplish this is to conditionally compile an XmlnsDefinition attribute into an assembly referenced by the project. When the conditional symbol is defined, the WPF XAML compiler will consider the namespace defined by the XmlnsDefinition attribute as known. If the conditional is not defined, the assembly will not have the XmlnsDefinition attribute and the namespace will be considered unknown. This can be done by adding the following code to a referenced assembly,
Remember, this must be an assembly referenced by the project, not in the project itself (I explain why below).
You can then conditionally include a label, as in,
The label will only be included in the beta version of the assembly, not the production version (assuming that BETA is not defined for the production version, a mistake I have made before...). You can even make it more complicated by having other dummy namespaces for other versions and a fallback to catch when the build configuration was not correctly set up, such as,
I believe this technique is superior to other techniques I have seen described involving data binding and/or triggers because the resulting production version has no runtime overhead for the beta label. The production choice doesn't mention the label at all; the BAML file will not contain any reference to the label and no label will be created at runtime. It is equivalent deleting the entire alternate content block. Also, since it only uses XAML features, not WPF features, it is usable in non-WPF dialects.
If you adopt this technique, I recommend adding the dummy namespaces to an assembly that contains only XmlnsDefinition attributes. Since this assembly doesn't contain any code, the C# compiler will not include it among the references in the final assembly therefore you don't have to distribute it.
The reason you cannot include the XmlnsDefinition in the project itself is because the XAML is compiled before the assembly is built (most of the time, I will get into the details of this in a later post). The compiler cannot know what attributes are in the project until the project's assembly has been built. Since the BAML file needs to be in included in the assembly, it must be compiled before the assembly. This is a catch-22 so the compiler ignores XmlnsDefintiion attributes in the project assembly but will respect attributes in referenced assemblies (which are built before the XAML is compiled).
In a future version of XAML we might consider adding formal support for conditional compilation but, for now, you can get the effect of conditional compilation through the use of AlternateContent, even if it is a bit indirect.
1:55 PM | Comments [1] | #XAML
05/25/2010 3:58 AM
Hello!I tried this example with a bit more complex structure Window>StackPanel and immediately get error, something like "cannot convert ListBox to ListBoxItem" (they were inside a conditional tag).
Can you check it, please?
Thorn | mailto:thornikAT NOSPAMgmail dot com | thornikAT NOSPAMgmail dot com