This article is taking things further still – the ability to merge in your own displays in the viewmodel aided view including:
- how to mold data from your model into viewmodels using the ViewModel-designer in Modlr.
- how such viewmodels lend themselves to act as the complete definition of a view if you just dress them up with a few user interface hints (UI-Hints) – and how easy that is in the Modlr viewmodel designer.
- effective way to get an administrative UI up and running in minutes instead of hours.
Consider this simple model:
Accompanied by this viewmodel:
Here we display a list of all flowers by name, and a some details on the focused flower – the name and the number of leaves – but also a ViewModelColumn called “HowItLooks”.
The “HowItLooks” column has the flag Content-Override set. When this flag is set the well-behaving ViewModelUserControl should allow for the developer to inject their own display – with a callback event or the like. At this point you can associate a WPF UI control in design ti
When the ViewModelColumn is selected the property inspector looks like this ☛
The ContentOverride and ContentOverrideTypeDesignTimePath are shown whenever the ContentOverride is true.
The ContentOverride expects the Assembly without the dll extension, a semi colon , and the namespace and type of the UserControl you want to display here. <AssemblynamewithoutDLLExtension>;<NameSpace>.<TypeOfExternalUIControl>.
The type you want to use must implement this interface:
namespace Eco.ViewModel.Runtime { public interface IExternalWECPOFUIComponent { // Summary: // Go like this: (vmc.SpawnedComponents["control"] as Grid).Children.Add(this); void InstallYourSelf(ViewModelColumn vmc, bool isDesignTime); string TheRequirementsToShowDeveloperInDesignTime(); } }
A simple sample
In WPF it is fairly simple to draw something that looks like a flower:
void DrawingArea_LayoutUpdated(object sender, EventArgs e) { if (NumberOfLeafs != _drawnleaves) { DrawingArea.Children.Clear(); Point center = new Point(DrawingArea.ActualWidth / 2, DrawingArea.ActualHeight / 2); double leafdeg = 0; for (int i = 0; i < NumberOfLeafs; i++) { Ellipse oneleaf = new Ellipse(); oneleaf.Width = 10; oneleaf.Height = center.Y; oneleaf.RenderTransform = new RotateTransform(leafdeg, 5, 0); oneleaf.Stroke = new SolidColorBrush(Colors.Black); oneleaf.Fill = new SolidColorBrush(Colors.Yellow); Canvas.SetLeft(oneleaf, center.X-5); Canvas.SetTop(oneleaf, center.Y); DrawingArea.Children.Add(oneleaf); leafdeg = (i+1)* 360 / NumberOfLeafs; } Ellipse pistills=new Ellipse() { Width = 20, Height = 20, Fill = new SolidColorBrush(Colors.Black) }; DrawingArea.Children.Add(pistills); Canvas.SetLeft(pistills, center.X-10); Canvas.SetTop(pistills, center.Y-10); _drawnleaves = NumberOfLeafs; } }
The code above draws the flower simulation based on a the value in a NumberOfLeafs property.
We want to be able to bind this property to a datasource – in WPF that implies a DependencyProperty:
public int NumberOfLeafs { get { return (int)GetValue(NumberOfLeafsProperty); } set { SetValue(NumberOfLeafsProperty, value); } } // Using a DependencyProperty as the backing store for NumberOfLeafs. This enables animation, styling, binding, etc... public static readonly DependencyProperty NumberOfLeafsProperty = DependencyProperty.Register("NumberOfLeaf", typeof(int), typeof(UserControl1), new UIPropertyMetadata(NumberOfLeafsChanged)); private static void NumberOfLeafsChanged(DependencyObject source, DependencyPropertyChangedEventArgs e) { (source as UserControl1).DrawingArea.InvalidateVisual(); }