Friday, February 11, 2011

SilverPaint - Drawing Dynamic Shapes in Silverlight 3

This is a quick demonstration that focuses on some of the geometric shape drawing features that are available in Silverlight and how to use those features in code.

Live Demo: Drawing Dynamic Silverlight Shapes


The following code excerpts show the highlights of performing the primary shape drawing functions:
  • Dynamic shape creation
  • Sizing calculations
  • Brushes
  • Dynamic event handlers
  • Shape re-sizing
  • Shape movement 
///

/// Draws the desired geometrical shape.  This quick example app uses
/// ellipses and rectangles, but others would work here as well.
///
private void DrawShape(Shape shape, SolidColorBrush brush)
{
    double x = 0.0, y = 0.0;

    // These calcs are required to handle sizing in any direction
    if (_ptStart.X > _mX)
    {
        shape.Width = _ptStart.X - _mX;
        x = _mX;
    }
    else
    {
        shape.Width = _mX - _ptStart.X;
        x = _ptStart.X;
    }


    if (_ptStart.Y > _mY)
    
{
        
shape.Height = _ptStart.Y - _mY;
        
y = _mY;
    
}
    
else
    
{
        
shape.Height = _mY - _ptStart.Y;
        
y = _ptStart.Y;
    
}

    // Set the brushes
    
shape.Fill = brush;
    
shape.StrokeThickness = 1;
    
shape.Stroke = _whiteBrush;

    // Set the shape's coordinates
    shape.SetValue(Canvas.LeftProperty, x);
    shape.SetValue(Canvas.TopProperty, y);

    if (_shapeLast != null)
    {
        LayoutRoot.Children.Remove(_shapeLast);
    }

    
// Set the name, tooltip and add the event handlers
    shape.Name = "DynamicShape" + _shapeCount.ToString();
    ToolTipService.SetToolTip(shape, shape.Name + "\r\n" + shape.GetType().ToString());

    shape.MouseEnter += new MouseEventHandler(shape_MouseEnter);
    shape.MouseLeave += new MouseEventHandler(shape_MouseLeave);
    shape.MouseLeftButtonDown += new MouseButtonEventHandler(shape_MouseLeftButtonDown);
    shape.MouseLeftButtonUp += new MouseButtonEventHandler(shape_MouseLeftButtonUp);

    
// Add the shape to the canvas
    _shapeLast = shape;
    _shapeCount++;
    LayoutRoot.Children.Add(shape);
}

///

/// This is the method where the shapes are drawn, resized and moved.
///

private void LayoutRoot_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
    
// Update mouse coordinates
    _mX = e.GetPosition(sender as UIElement).X;
    _mY = e.GetPosition(sender as UIElement).Y;
    ctlCoords.Text = "(" + _mX + " ," + _mY + ")";

    
// If enabled, add event info to the console
    if (chkTrackMouse.IsChecked == true)
    {
        AddConsoleMsg("LayoutRoot_MouseMove: X=" + _mX + ", Y=" + _mY);
    }

    
// Perform a hittest to make sure we're operating within the bounds of our
    
// drawing surface
    IEnumerable elements;
    elements = VisualTreeHelper.FindElementsInHostCoordinates(
        new Point(_mX, _mY), ctlBounds as UIElement);

    if (elements.Any())
    {
        
// If enabled, draw the gridlines
        if (chkGridlines.IsChecked == true)
        {
            DrawGridlines();
        }

        
// If enabled, draw an ellipse
        if (_isLeftMouseButtonDown == true && _isDrawEllipse)
        {
            Ellipse ellipse = new Ellipse();
            DrawShape(ellipse, _brushes[_randBrush.Next(0,_brushes.Count)]);
        }

        
// If enabled, draw a rectangle
        if (_isLeftMouseButtonDown == true && _isDrawRect)
        {
            Rectangle rect = new Rectangle();
            DrawShape(rect, _brushes[_randBrush.Next(0, _brushes.Count)]);
        }

        
// If enabled, draw a line
        if (_isLeftMouseButtonDown == true && _isDrawLine)
        {
            Line line = new Line();
            DrawLine(line);
        }

        
// If a shape is moving
        if (_isShapeMoving)
        {
            double x = _mX - _shapeMove.Width / 2;
            double y = _mY - _shapeMove.Height / 2;

            
// Move the shape
            _shapeMove.SetValue(Canvas.LeftProperty, x);
            _shapeMove.SetValue(Canvas.TopProperty, y);
        }
    }
    else
    {
        // We're outside of the bounds of our drawing surface so remove the gridlines
        RemoveGridlines();
    }
}
You can download the full source here: Drawing Dynamic Silverlight Shapes Demo. This requires Visual Studio 2008 and Silverlight 3 development tools (Expression Blend is notrequired but would be useful as well).

1 comment:

  1. This is extremely helpful and a great introduction. Have you added any other paint-like functionality you can share?

    ReplyDelete