WPF DynamicResource ObservableCollection
This article describes how to declare an ObservableCollection of a complex type in XAML for use as a DynamicResource.
You can fill it declaratively with records in XAML and or later in code.
Use Cases and Plusses
Simplified binding of lists - especially for controls which are not in the visual tree.
Binding of data which is not particularly suited for inclusion in a ViewModel.
Simplifying sharing of the same collection across multiple views.
Designer friendly - a collection filled declaratively or in a Window's parameterless constructor will be visible in Blend to the designer. That same collection can be filled with default data for the designer and also used at run time. This obviates the need to have two collections - one for design and another for run time.
This approach addresses a question which comes up in forums regularly: "Can I declare a collection in XAML".
Well you can but without the work round described below it will have to be a static Arraylist of a value type that's in MSCorlib.
Background
Most business applications have a lot of collections of data which are displayed.
Quite a few of these are very dynamic and the user will want a subset which is real time or thereabouts - top salesman, latest 20 orders, sales figures or current stock values.
Other collections rarely change or are completely static. For such static collections, declaring them in XAML can be convenient.
For rarely changing collections or occasionally connected we can imagine a mechanism which gets the data and caches it in a local database or as xaml on the client, presents this initially. Later reading fresh data from a database and replacing the contents of the collection. You could even supply a flat .xaml flat file and merge that in app.xaml. Manipulate this at run time then WriteXaml.Save() your updated collection back to disk.
You could create an ObservableCollection in code and then programmatically set the ItemsSource of a control to it, but then you cannot declare your StaticResource binding in XAML at design time and a designer would not be able to see any data in the control in Blend.
Simple Arraylist
Before looking at the complicated way, it's perhaps worth illustrating the straight forward approach. For less demanding static requirements an Arraylist of objects might do the trick. This can be value types as illustrated here, or it could even be complex types.
Just add a reference to System.Collections and System
xmlns:col="clr-namespace:System.Collections;assembly=mscorlib"
xmlns:sys="clr-namespace:System;assembly=mscorlib" >
Then you can declare something in XAML
<Window.Resources>
<col:ArrayList x:Key="Vowels">
<sys:String>A</sys:String>
<sys:String>E</sys:String>
<sys:String>I</sys:String>
<sys:String>O</sys:String>
<sys:String>U</sys:String>
</col:ArrayList>
</Window.Resources>
ObservableCollection of a Complex Type
The tricky bit with this is that you have to declare a class inheriting from ObservableCollection<T> where T is the complex type you wish to use.
<Application.Resources>
<local:ColourCollection x:Key="ColourSource">
<local:SimpleColour ColourString="Yellow" Id="1"/>
<local:SimpleColour ColourString="Blue" Id="2"/>
<local:SimpleColour ColourString="Red" Id="3"/>
<local:SimpleColour ColourString="Green" Id="4"/>
<local:SimpleColour ColourString="Purple" Id="5"/>
</local:ColourCollection>
</Application.Resources>
Here's the rather strange looking class which allows you to use an ObservableCollection<T>:
public class ColourCollection : ObservableCollection<SimpleColour>
{
}
You also need that type:
public class SimpleColour
{
public int Id { get; set; }
public string ColourString { get; set; }
}
The properties of that class could include more complex types such as SolidColourBrush.
Hit f6 to compile and you can then use this in your XAML.
You first need a reference to your project though:
xmlns:local="clr-namespace:wpf_ComboBoxColumn"
local: refers to the namespace containing collection and type.
You can add entries to that collection in XAML where you declare it, or leave it empty and fill the collection at run time. Perhaps from some local cache or a remote database.
ColourCollection cc = Application.Current.Resources["ColourSource"] as ColourCollection;
cc.Clear();
cc.Add(new SimpleColour { ColourString = "Yellow", Id = 1 });
cc.Add(new SimpleColour { ColourString = "Blue", Id = 2 });
cc.Add(new SimpleColour { ColourString = "Red", Id = 3 });
cc.Add(new SimpleColour { ColourString = "Green", Id = 4 });
cc.Add(new SimpleColour { ColourString = "Purple", Id = 5 });
Application.Current.Resources["ColourSource"] = cc;
The MainWIndow in the sample solution WPF_ComboBocxColumn is bound to a ViewModel which will be dynamically filled at run time like many business systems so and you cannot see any data whilst designing. If you set up a control using this dynamic resource directly you can design with data showing. This approach can be very useful in giving a better idea of look and feel.
If you download the sample linked below you can experiment with that.
Create a new WIndow - Window1.
Paste in the following:
<Grid>
<DataGrid ItemsSource="{DynamicResource ColourSource}" />
</Grid>
Make sure the collection is filled in App.xaml:
<Application.Resources>
<local:ColourCollection x:Key="ColourSource">
<local:SimpleColour ColourString="Yellow" Id="1"/>
<local:SimpleColour ColourString="Blue" Id="2"/>
<local:SimpleColour ColourString="Red" Id="3"/>
<local:SimpleColour ColourString="Green" Id="4"/>
<local:SimpleColour ColourString="Purple" Id="5"/>
</local:ColourCollection>
</Application.Resources>
When you switch back to WIndow1 you will be able to see the data in the Designer
In blend:
You can download the sample solution here