To create a property with list of available options we usually use SelectionFactory. One SelectionFactory class can be used on many properties. But sometimes, for specific property, we want one or two extra selection items. The SelectOne and SelectMany attributes have SelectionFactoryType property which is a factory type not the factory instance. In this article I’d like to show how create SelectionFactory with parameters.
Example
Let say that we have two properties on the StartPage: ForegroundColors and BackgroundColors. Both should be list of available colors (red, green and blue). But for ForegroundColors we also need orange and yellow and for BackgroundColors we need extra brown color.
Implementation
The selection factory class has to implement ISelectionFactory interface which expose GetSelections method. The factory with the default colors can be implemented as:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
public class ColorsSelectionFactory : ISelectionFactory { public IEnumerable<ISelectItem> GetSelections(ExtendedMetadata metadata) { var defaultColors = new List<SelectItem> { new SelectItem { Value = "1", Text = "Red" }, new SelectItem { Value = "2", Text = "Green" }, new SelectItem { Value = "3", Text = "Blue" } }; return defaultColors; } } |
The GetSelections method has ExtendedMetadata parameter. Using this parameter we have access to all attributes that annotate the property. So we could create new attrbute ColorOptionAttribute that for adding extra colors to the factory.
1 2 3 4 5 6 7 8 9 10 11 12 |
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] public class ColorOptionAttribute : Attribute { public string Value { get; set; } public string Name { get; set; } public ColorOptionAttribute(string name, string value) { Name = name; Value = value; } } |
Now we can read the attribute in the factory by using metadata.Attributes property.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
public class ColorsSelectionFactory : ISelectionFactory { public IEnumerable<ISelectItem> GetSelections(ExtendedMetadata metadata) { var defaultColors = new List<SelectItem> { new SelectItem { Value = "1", Text = "Red" }, new SelectItem { Value = "2", Text = "Green" }, new SelectItem { Value = "3", Text = "Blue" } }; defaultColors.AddRange(metadata.Attributes.OfType<ColorOptionAttribute>().Select(x=>new SelectItem { Text = x.Name, Value = x.Value})); return defaultColors; } } |
The attribute has AllowMultiple property set to true, so it can be used on the property more than once.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public class StartPage : PageData { [Display(Name = "Background colors")] [SelectMany(SelectionFactoryType = typeof(ColorsSelectionFactory))] [ColorOption("Brown", "200")] public virtual string BackgroundColors { get; set; } [Display(Name = "Foreground colors")] [SelectMany(SelectionFactoryType = typeof(ColorsSelectionFactory))] [ColorOption("Orange", "100")] [ColorOption("Yellow", "101")] public virtual string ForegroundColors { get; set; } } |