none
x:Array markup extension as ItemsSource for ComboBox

    Question

  • I just have encountered a weird behavior of x:Array markup extension when it's used as ItemsSource of the ComboBox.

    I have an enumeration and the x:Array defined in the Resources block of the Application in App.xaml:
    enumeration and corresponding x:Array in App.xaml resources block

    public enum Dpi
    {       

    DirectMail_300,
    Newspaper_150,
    Digital_Newspaper_72,
    Magazine_300,
    Outdoor_42,
    Website_72

    }



    <Application.Resources>

    <x:Array Type="{x:Type library:LtDpi}" x:Key="AllDpi">
      <x:Static Member="library:LtDpi.DirectMail_300" />
      <x:Static Member="library:LtDpi.Magazine_300" />
      <x:Static Member="library:LtDpi.Newspaper_150" />
      <x:Static Member="library:LtDpi.Website_72" />
      <x:Static Member="library:LtDpi.Digital_Newspaper_72" />
      <x:Static Member="library:LtDpi.Outdoor_42" />       
    </x:Array>

    </Application.Resources>


    I'm trying to use this array extension to fill the ComboBox:
    Scenario 1: Throws an exception

    <Window ...>

      <ComboBox ItemsSource="{StaticResource AllDpi}"/>

    </Window>

    Scenario 2: Works well

    <Window ...>

      <Window.Resources>

        <Style TargetType="ComboBox">

          <Setter Property="ItemsSource" Value="{StaticResource AllDpi}" />

        </Style>

      </Window.Resources>

      <ComboBox />

    </Window>


    As the headings sayin the first scenario I'm getting an exception with the following message. The second scenario works well and I can see the ComboBox filled with my enum members.
    Exception

    System.Windows.Markup.XamlParseException: Cannot convert the value in attribute 'ItemsSource' to object of type 'System.Collections.IEnumerable'. 'System.Windows.Markup.ArrayExtension' is not a valid value for property 'ItemsSource'.  Error at object 'System.Windows.Controls.ComboBox' in markup file 'Window1;component/Window1.xaml' Line 31 Position 15. ---> System.ArgumentException: 'System.Windows.Markup.ArrayExtension' is not a valid value for property 'ItemsSource'.


    I dont mind setting the ItemsSource in the ComboBox Style, but it does not make any sense. Why am I getting the exception?

    Thanks
    Anton

    Edit:
    I just have found that if the array markup extension is declared in the Window's Resources block - no exception is thrown:

    works fine

    <Window ...>

    <Window.Resources>

    <x:Array Type="{x:Type library:LtDpi}" x:Key="AllDpi">
      <x:Static Member="library:LtDpi.DirectMail_300" />
      <x:Static Member="library:LtDpi.Magazine_300" />
      <x:Static Member="library:LtDpi.Newspaper_150" />
      <x:Static Member="library:LtDpi.Website_72" />
      <x:Static Member="library:LtDpi.Digital_Newspaper_72" />
      <x:Static Member="library:LtDpi.Outdoor_42" />       
    </x:Array>

    </Window.Resources>

      <ComboBox ItemsSource="{StaticResource AllDpi}"/>

    </Window>

    Sunday, November 11, 2007 12:13 AM

Answers

  • Anton__ wrote:

    I dont mind setting the ItemsSource in the ComboBox Style, but it does not make any sense. Why am I getting the exception?

     

    x:Array is a markup extension.  As such, it provides a value to the parser at parse-time.  The type of value it provides depends on the parser context that is used to parse the xaml.  A different parser context is used to parse resources, so many markup extensions provide an unresolved value when resolved as part of a resource dictionary.  That unresolved extension eventually gets fully resolved when the resource is applied to an element within the tree.

     

    So to answer the Why? question, when the StaticResource reference is used in a style, the Array extension is returning a value of type ArrayExtension... instead of an actual enumerable array.

     

    However, you can still set the ItemsSource in your style...  simply use a binding to the array resource.  The {Binding} markup extension always returns a BindingExpression.  A BindingExpression can be set as the value of any DP (like ItemsSource).  Then at runtime when the style is applied, the Array extension will be fully resolved to an enumerable collection.

     

    So your style looks like this:

     

    Code Block

     

    <Style TargetType="ComboBox">

      <Setter Property="ItemsSource"

          Value="{Binding Source={StaticResource AllDpi}}" />

    </Style>

     

     

    NOW... Another approach for your scenario is to not use an Array at all to list your enum members.  If you use an array and later change the enum values, you have to remember to update the markup too.  A better approach is to simply use an ObjectDataProvider to dynamically get the enum values in an enumerable collection:

     

    Code Block

     

    <ObjectDataProvider x:Key="AllDpi"

        MethodName="GetValues"

        ObjectType="{x:Type library:LtDpi}">

      <ObjectDataProvider.MethodParameters>

        <x:Type TypeName="library:LtDpi"/>

      </ObjectDataProvider.MethodParameters>

    </ObjectDataProvider>

     

     

    You will always set this as your ItemsSource using a binding, since a binding knows to treat an object data provider as a collection.

     

    Code Block

     

    <ComboBox ItemsSource="{Binding Source={StaticResource AllDpi}}" />

     

     

    Or you can set it in the style with a binding exactly as shown earlier.

    Sunday, November 11, 2007 7:15 AM