Create your own Designer or Introduction To Custom Designers – Part 2: UI, Glyphs

17 בינואר 2008

In my last post I have demonstrated how to create your own Designer, in this post I will continue on demonstrating on how to create your own Designer.


My goal in this series of posts is to explain how to create and extended Designers. For this reason I have created a sample. This plain sample is a UserControl that contains an PictureBox and a Label. Using many of this controls can be a bit frustrating, since we can change the Image of the PictureBox without encapsulate the Image Property. As I mention in my last post we would like to avoid this. This is just a simple example of how to use and extend your Control Designer.


This is how it looks:


control101


The UI in your Designer is implemented by Glyphs, each on of your Glyphs is basically a UI access point that during designing you can use to manipulate your control with.


Step 1: Create a Glyph, first you must inherit from the Glyph class, our Implementation to the Glyph should contains reference to the ControlDesigner, Adorner and the various services. This will help our work in designing our Control.




public class PictureSelectionGlyph : Glyph


{


    //References to services that we will need.


    private BehaviorService m_BehaviorService = null;


    private IComponentChangeService m_ComponentChangeService = null;


    private ISelectionService m_SelectionService = null;


    //The designer reference


    private IDesigner m_ComponentDesigner = null;


    //The adorner reference.


    private Adorner m_adorner = null;


    //The control that is being designed.


    private Control m_relatedControl = null;


    // This defines the bounds used for hit testing.


    protected Rectangle m_HitTestBoundsValue;


    // This is the cursor returned if hit test is positive.


    protected Cursor hitTestCursor = Cursors.Hand;


 


All of these arguments are pass to the glyph by the designer so all the extra work we have to do is to keep reference to it.




public PictureSelectionGlyph(BehaviorService behaviorService, IComponentChangeService changeService,


            ISelectionService selectionService,IDesigner relatedDesigner,Adorner anchorAdorner): base(new PictureSelectorBehavior(relatedDesigner))


{


Step 2: Painting our Glyph. The glyph is a UI that is painted by GDI+, so we have to make sure that the glyph is painted in the right way (Location, Size…). First we must decide how we want our glyph to look like. Keep in mind that glyphs are only the access points and should not be to fancy that will shadow the control. this is how it should look like:


You may have notice that we have to calculate the location and size of our Glyph. In my example I have painted the glyph in the middle of the control that been Designed.




//This method renders the PictureSelectionGlyph as a filled rectangle,


//in the center of the designed control.


public override void Paint(PaintEventArgs e)


{


     using (Brush b = new SolidBrush(Color.DarkRed))


     {


         Pen p = new Pen(b, 2f);


         e.Graphics.DrawRectangle(p, Bounds);


         using (Brush fillBrush = new LinearGradientBrush(this.Bounds, Color.DarkRed, Color.Gold, 180f))


         {


             e.Graphics.FillRectangle(fillBrush, Bounds);


         }


     }


}


 


Step 3: Assigning Behavior to our Glyph.


Great! now We have painted a glyph, what is next? Behavior  is the class that responsible for handling and manipulating our Control.


As you might have noticed in the Glyph class Constructor we have Created a new instance of PictureSelectorBehavior, this class is the behavior class of the Glyph. If Glyph is the looks then the Behavior is the Brains.



//This Behavior specifies mouse and keyboard handling when


//Glyph is active. This happens when PictureSelectionGlyph.GetHitTest returns a non-null value.


internal class PictureSelectorBehavior : Behavior


{


   private IDesigner m_relatedDesigner = null;


   private Control m_relatedControl = null;


   private OpenFileDialog m_openFileDialog;


   internal PictureSelectorBehavior(IDesigner relatedDesigner)


   {


      this.m_relatedDesigner = relatedDesigner;


      this.m_relatedControl = relatedDesigner.Component as Control;


   }


Our behavior should inherits from Behavior and Initialize in Glyph Constructor


We would like to keep reference for our Designer, Control this will help us manipulate our Designed Control.


All that's left is to decide how our control react, in my case I had overridden the OnMouseDoubleClick:



public override bool OnMouseDoubleClick(Glyph g, MouseButtons button, Point mouseLoc)


{


    if (button != MouseButtons.Left)


       return false;


   PropertyDescriptor bounds = TypeDescriptor.GetProperties(g)["Bounds"];


   if (((Rectangle)bounds.GetValue(g)).Contains(mouseLoc))


   {


       if(BehaviorOenFileDialog.ShowDialog(m_relatedControl)  == DialogResult.OK)


       {


           PropertyDescriptor imageLocationPropertyDescriptor = TypeDescriptor.GetProperties(m_relatedControl)["ImageLocation"];


               imageLocationPropertyDescriptor.SetValue(m_relatedControl, BehaviorOenFileDialog.FileName);


       }


       return true;


   }


   return base.OnMouseDown(g, button, mouseLoc);


}


In the OnMouseDoubleClick we check that the event occurs on the Glyph bounds if so we perform the desire action, In my case I open a dialog that will ask us to choose the physical location of the Image In our PictureBox  – Sweet!.


Note: If you want that the Image will be saved in the Resources of our project use PropertyDescriptor to set the new value of the Image property of PictureBox.


This is how it looks in Design mode:


designer101


DoubleClick to open the dialog and select a new Image.


* Source Code will be available soon.


Next post will feature new abilities such as Verbs and SmartTags.


*njoy!

הוסף תגובה
facebook linkedin twitter email

כתיבת תגובה

האימייל לא יוצג באתר. (*) שדות חובה מסומנים