views:

892

answers:

4

I've search high and low and can't find an answer to this. I have two questions

  1. How do you create an array or collection in XAML. I've got an array I want to stick in there and bind to a combo box. My first idea was to put an ItemsControl in a resource dictionary, but the ItemsSource of a combo box expects IEnumerable so that didn't work.

Here's what I've tried in my resource dictionary and neither works

<ItemsControl x:Key="stateList">
    <sys:String>AL</sys:String>
    <sys:String>CA</sys:String>
    <sys:String>CN</sys:String>
</ItemsControl>
<ItemsControl x:Key="stateList2">
    <ComboBoxItem>AL</ComboBoxItem>
    <ComboBoxItem>CA</ComboBoxItem>
    <ComboBoxItem>CN</ComboBoxItem>
</ItemsControl>

and here's how I bind to it

<ComboBox SelectedValue="{Binding Path=State}" ItemsSource="{Binding Source={StaticResource stateList2}}"  >

                    </ComboBox>

EDIT: UPDATED

I got this first part to work this way

 <col:ArrayList x:Key="stateList3">
    <sys:String>AL</sys:String>
    <sys:String>CA</sys:String>
    <sys:String>CN</sys:String>
</col:ArrayList>

However, I'd rather not use an array list, I'd like to use a generic list so if anyone knows how please let me know.

EDIT UPDATE: I guess XAML has very limited support for generics so maybe an array list is the best I can do for now, but I would still like help on the second question if anyone has an anser

2nd. I've tried referencing a merged resource dictionary in my XAML and had problems because under Window.resources I had more than just the dictionary so it required me to add x:Key. Once I add the key, the system can no longer find the items in my resource dictionary. I had to move the merged dictionary to Grid.Resources instead. Ideally I'd like to reference the merged dictionary in the app.xaml but I have the same problem

Here's some sample code. This first part required an x:key to compile because I have converter and it complained that every item must have a key if there is more than one

<UserControl.Resources>
    <win:BooleanToVisibilityConverter x:Key="VisibilityConverter" />
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="/ResourcesD.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</UserControl.Resources>

I had to change it to this

<UI:BaseStep.Resources>
    <win:BooleanToVisibilityConverter x:Key="VisibilityConverter" />             
</UI:BaseStep.Resources>
<Grid>
    <Grid.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/ResourcesD.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Grid.Resources>
</Grid>

Thank you

A: 

Please correct me if I'm wrong but I think you want something like this?

<Grid.Resources>
  <local:MyCustomCollection x:Key="local:MyCustomCollection"/>
</Brid.Resources>

At the top of your window you'd have a property:

xmlns:local="clr-namespace:MyNamespace"

And inside your code you'd have:

MyCustomCollection  custCol = MyGrid.Resources["MyCustomCollection"] as MyCustomCollection;

Binding would happen on a control with a property something like this:

ItemsSource="{StaticResource MyCustomCollection}"
Brian R. Bondy
Not really. I want a collection in a resource dictionary because I want to share the collection among several controls and windows. It's a list of states. I want to be able to bind to the list of states. I don't want to access it in the code behind.
Chris Cap
OK sorry I'm unsure off hand, I'll keep this answer here in case it helps anyone else.
Brian R. Bondy
A: 

If you add resource dictionary inside Window's resources, you will not be able to access it everywhere, instead you should add in "App"'s resources (check out App.xaml file).

<App.Resources> 
    <win:BooleanToVisibilityConverter x:Key="VisibilityConverter" /> 
    <ResourceDictionary> 
        <ResourceDictionary.MergedDictionaries> 
            <ResourceDictionary Source="/ResourcesD.xaml" /> 
        </ResourceDictionary.MergedDictionaries> 
    </ResourceDictionary> 
</App.Resources> 

This will be available in every WPF object regardless of creating any inheritance hierarchy.

Akash Kava
I did try that and it's what I wanted, however, it still complains about required a resource key and when I add the resource key, it no longer resolves.
Chris Cap
I think you can move your converter inside your ResourcesD.xaml and then you can have only one resource dictionary element.
Akash Kava
Well, I have several other resources in the app.xaml, I'd have to move all of them out. Something just seems strange about that. Do I need to bind to it with the x:key reference somehow.
Chris Cap
Nope, i dont think so you can do that, I think the best way to do is, you can have multiple resource dictionaries... you can have one "ConverterResources.xaml" and "CollectionResources.xaml" and you can merge multiple resources in resource dictionary, however doing this, you will be able to seperate everything logically as well as solve your problem.
Akash Kava
That does make sense. I tried that and it kind of worked. However, it's now failing to create an object that I had in my app.xaml. Doesn't give me any worthwhile debugging information. I changed things around a bit so that the application would still work. Kind of an unsavory solution, but the resources are resolving. Thank you
Chris Cap
+1  A: 

For the resources, you just need to mover your additional converter into the newly declared ResourceDictionary:

<App.Resources> 
    <ResourceDictionary> 
        <ResourceDictionary.MergedDictionaries> 
            <ResourceDictionary Source="/ResourcesD.xaml" /> 
        </ResourceDictionary.MergedDictionaries> 

    <win:BooleanToVisibilityConverter x:Key="VisibilityConverter" /> 
    </ResourceDictionary> 
</App.Resources> 
Abe Heidebrecht
+1  A: 

As far as I understand your problem you want to bind a ComboBox (or a ListBox) with an array of items, right? If you want items from some external data source, you can just make use of handy DataContext property. Search MSDN for more on this. However, if you do want a manual collection, do it this way:

Create your own class:

public class StringCollection : ObservableCollection<string> { }

and now use it like this:

<Window.Resources>
    <local:StringCollection x:Key="stringCollection">
        <sys:String>Hello</sys:String>
        <sys:String>World</sys:String>
    </local:stringCollection>
</Window.Resources>

...

    <ListBox
        Margin="15"
        ItemsSource="{StaticResource stringCollection}" />

Or, if you want more generic collection create a class like this:

public class ObjectCollection : ObservableCollection<object> { }

and use it like this:

    <local:ObjectCollection x:Key="objectCollection">
        <sys:String>Hello</sys:String>
        <TextBlock>World</TextBlock>
        <sys:Int32>12345</sys:Int32>
    </local:ObjectCollection>

    ...

    <ComboBox
        Margin="15"
        ItemsSource="{StaticResource objectCollection}" />



You may also want to make use of some in-built classes like Int32Collection that implements IEnumerable. You can use them directly as a resource.


The Resources property (of any FrameworkElement like Window, UserControl, or Application) is of type ResourceDictionary not collection of resource dictionaries! so you can't do like this:

<UserControl.Resources>

    <!-- The first RD -->
    <!--<ResourceDictionary>
        <win:BooleanToVisibilityConverter x:Key="VisibilityConverter" />
    </ResourceDictionary>-->

    <!-- Second RD!!! -->
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="/ResourcesD.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</UserControl.Resources>

Instead do like this:

<UserControl.Resources>

    <!-- 
        There should be only 1 main RD, 
        Merge other RDs, if any
     -->
    <ResourceDictionary>

        <!-- First Resource -->
        <win:BooleanToVisibilityConverter x:Key="VisibilityConverter" />

        <!-- Second Resource -->
        <ResourceDictionary.MergedDictionaries>
            <!-- Now, there can be multiple RDs -->
            <ResourceDictionary Source="/ResourcesA.xaml" />
            <ResourceDictionary Source="/ResourcesB.xaml" />
            <ResourceDictionary Source="/ResourcesC.xaml" />
            <ResourceDictionary Source="/ResourcesD.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>

</UserControl.Resources>

Hope this helps.
Regards,
Mihir Gokani

Mihir Gokani
That's an interesting approach. In my case it doesn't really need to be observable, but I suppose it would work in my case. Any idea on solving the other problem of supplying a resource key and having the resolution fail
Chris Cap
OK, i've added answer for your second question. Is this what you are looking for?
Mihir Gokani
oops! I think my second answer is similar to that of @Abe
Mihir Gokani
Thanks a lot, that explanation really makes sense
Chris Cap
any idea why moving a declaration from the app.xaml to resource dictionary in another folder would throw an error? I have all the correct namespaces specified.
Chris Cap
What kind of error are you getting? Have you given correct path for RD? like `"/FolderName/MyRD.xaml"`?
Mihir Gokani
Don't get me wrong, Chris, but I think you should ask this as a separate question since both are unrelated. (You could even have separated 2 questions you asked previously. This simplifies search and avoids lengthy answers.
Mihir Gokani