Search code examples
c#.netwpfxamlenums

Why can I use an enum as a XAML tag?


Why does the WPF/XAML code below work? Why can an enum be used as a XAML tag? Also, why can the converter parameter be more than one enum value? See below how I pass in Running and Setup. I haven't been able to find any documentation online that explains how both of these things work.

<local:CircleSpinner.Visibility>
    <Binding
     Path="CompletionStatus"
     ElementName="_this"
     Converter="{converters:VisibleIfEqualConverter}">
         <Binding.ConverterParameter>
             <enums:ExperimentCompletionStatusEnum>Running,Setup</enums:ExperimentCompletionStatusEnum>
         </Binding.ConverterParameter>
    </Binding>
    <!-- ... -->

Solution

  • Why can an enum be used as a XAML tag?

    It is designed like this, see the documentation for reference: XAML Syntax In Detail.

    Defining objects by using tags in XAML is referred to as Object Element Syntax.

    <Button/>
    

    Object element syntax is the XAML markup syntax that instantiates a CLR class or structure by declaring an XML element. This syntax resembles the element syntax of other markup languages such as HTML. Object element syntax begins with a left angle bracket (<), followed immediately by the type name of the class or structure being instantiated. [...]

    XAML as implemented by .NET has a set of rules that map object elements into types, attributes into properties or events, and XAML namespaces to CLR namespaces plus assembly.

    There is the Attribute Syntax that allows you to use properties as XAML attributes, here Content.

    <Button Content="This is the content of the button"/>
    

    Attribute syntax is the XAML markup syntax that sets a value for a property by declaring an attribute on an existing object element. The attribute name must match the CLR member name of the property of the class that backs the relevant object element. [...]

    There is the Property Element Syntax that is more verbose, but allows for nesting elements directly.

    <Button>
       <Button.Content>
          This is the content of the button
       </Button.Content>
    </Button>
    

    Instead of the property being specified as an attribute within the element tag, the property is specified using an opening element tag in elementTypeName.propertyName form, the value of the property is specified within, and then the property element is closed. [...]

    Why can the converter parameter be more than one enum value?

    An enum in C# can be decorated with the Flags attribute.

    Bit fields are generally used for lists of elements that might occur in combination, whereas enumeration constants are generally used for lists of mutually exclusive elements. Therefore, bit fields are designed to be combined with a bitwise OR operation to generate unnamed values, whereas enumerated constants are not.

    [Flags]
    public enum ColumnType
    {
       A = 1,
       B = 2,
       C = 4
    }
    

    This attribute allows an enum to be treated like a bit fields, e.g.:

    var bitwiseOrResult = A | B;
    

    That is why you can specify multiple values comma-separated, which acts as bitwise OR like above. This is useful to specify multiple values at once. For example, there is a ModifierKeys enum, declared with the Flags attribute, so you can have multiple modifiers, e.g. Ctrl + Shift.

    How does the conversion magically work?

    How does XAML even know how to convert a string in XAML to enum or how to convert a comma separated list of strings? The answer is type converters.

    In the .NET Framework, the TypeConverter class serves a particular purpose as part of the implementation for a managed custom class that can be used as a property value in XAML attribute usage. [...]

    When you set an attribute value in a XAML file, the initial type of that value is a string in pure text. Even other primitives such as Double are initially text strings to a XAML processor. [...]

    If the value is an enumeration, the string is used to check for a name match to a named constant in that enumeration.

    In short, a type converter is called to convert from string to the declared type. There are several built-in converters, like the EnumConverter. See the reference source here, if you are interested.