Custom controls in ViewModel aided Views
No edit summary
No edit summary
Line 32: Line 32:


=== A simple sample ===
=== A simple sample ===
It would be nice if the NumberOfLeaves could be visualized in some other way than just an integer – it would be nice if I could see the leaves.
In WPF it is fairly simple to draw something that looks like a flower:
In WPF it is fairly simple to draw something that looks like a flower:
  void DrawingArea_LayoutUpdated(object sender, EventArgs e)  
  void DrawingArea_LayoutUpdated(object sender, EventArgs e)  
Line 43: Line 41:
     double leafdeg = 0;    for (int i = 0; i < NumberOfLeafs; i++)   
     double leafdeg = 0;    for (int i = 0; i < NumberOfLeafs; i++)   
   {       
   {       
    Ellipse oneleaf = new Ellipse();       
        Ellipse oneleaf = new Ellipse();       
    oneleaf.Width = 10;       
        oneleaf.Width = 10;       
    oneleaf.Height = center.Y;       
        oneleaf.Height = center.Y;       
    oneleaf.RenderTransform = new RotateTransform(leafdeg, 5, 0);     
        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;  } }
        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();
}

Revision as of 01:53, 26 February 2017

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:

Image.png

Accompanied by this viewmodel:

Image1.png

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

Image2.png

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(); 
}
This page was edited 91 days ago on 02/10/2024. What links here