This is a piece of an ecommerce tool I built, I call it the Room Builder. It was what I learned Silverlight on - so this project has been brought up from Silverlight 1.1 Alpha version. In other words, you may see some bad practices in there. But it's still useful. Or could be to the right situation.
Specifically today I want to talk about one of the features of the tool, that is the part that allows me to designate a region of a photograph, name it, and wire events to it for use in the application.
There is a link to the finished tool, so you can see what I mean on the left side of this blog, under the section titled "links to some of my silverlight controls". If you hold your mouse over that link there should be a window pop up with instructions on it's use.
Regions of the photograph are targeted by clicking at key points along the perimeter of a path. In the case of our Room Builder, it would be the outline of a couch. After the path is defined, it is finalized with the click of a button. At that time, the defined region is turned into an object and added to the children of the canvas along with a click event so that object may be selected again.
You can download the source code for this Room Builder application here. It won't run for you, though, because there is no server side application with the correct web services. SORRY. If anyone really needs that piece, I'll be happy to send it. It's just time I didn't have tonight to spend. Sorry.
Anyway,
Here's the key points of this region building operation:
Click the Get Started Button, Cursor changes to a pencil.
public void StartMappingClick(object sender, RoutedEventArgs e)
{
//if it's not visible (Opacity), don't execute it. Stray Clicks.
if ( StartButton.Opacity < 1)
return;
if (_room == null || string.IsNullOrEmpty(_room.ProductID))
{
message.Text = "Please setup your room first.";
return;
}
_gettingRoom = false;
SBHideStartButton.Begin();
SBShowCancelButton.Begin();
SBShowEndButton.Begin();
//for our cursor
ImageMapperCanvas.Cursor = Cursors.None;
LayoutRoot.Cursor = Cursors.None;
///////////////////////
_points = new List();
// Capture mouse and update stat
CaptureMouse();
if (pencil != null)
{
pencil.Visibility = Visibility.Visible;
if (_positionLast != null)
movePencilToCurrentPosition((Point)_positionLast);
}
lastRectangle = "";
_bIn = true;
this.message.Text = "";
}
Click at each turning point of your region
private void HandleMouseLeftButtonDown(object sender, MouseEventArgs e)
{
// Capture mouse and update stat
Point pos = e.GetPosition(this);
if (_bIn)
{
//highlight the point and add it to the list
registerPoint( pos );
}
_positionLast = pos; //this is so we can track for edits.
}
private void registerPoint(Point pos)
{
//only register the point if it's inside the image.
if (!CheckCollision(pencil, ImageMapperCanvas))
return;
_points.Add(pos);
if (_points.Count == 1)
{
//mark the point
Ellipse el = new Ellipse();
el.SetValue(Canvas.LeftProperty, pos.X+20);
el.SetValue(Canvas.TopProperty, pos.Y+20 );
el.Width=2;
el.Height=2;
el.Stroke = new SolidColorBrush(Color);
el.StrokeThickness = 1;
el.SetValue(Line.NameProperty, lineName(_points.Count));
LayoutRoot.Children.Add(el);
}
else
{
//draw the polyline and add the line to the list.
//string of points
//
// Create new line
var line1 = new Line
{
X1 = _positionLast.Value.X,
Y1 = _positionLast.Value.Y,
X2 = pos.X,
Y2 = pos.Y,
Stroke = new SolidColorBrush(Color),
StrokeThickness = 1
};
line1.SetValue(Line.NameProperty, lineName(_points.Count));
LayoutRoot.Children.Add(line1);
}
}
Click the End Mapping Button
public void EndMappingClick(object sender, RoutedEventArgs e)
{
//if it's not visible (Opacity), don't execute it. Stray Clicks.
if (this.EndButton.Opacity < 1)
return;
SBHideStartButton.Begin();
SBHideEndButton.Begin();
SBShowcontrolgrid.Begin();
// Release mouse and update stat
ReleaseMouseCapture();
ImageMapperCanvas.Cursor = Cursors.Stylus;
LayoutRoot.Cursor = Cursors.Arrow;
if (pencil != null)
{
pencil.Visibility = Visibility.Collapsed;
}
if (_bIn)
{
_ictr++;
//we could switch this out based on a selected tool.
// MapItemBO newMapItem = drawRectangle();
MapItemBO newMapItem = drawPolygon();
if (newMapItem != null)
persistMapItem( newMapItem );
_bIn = false;
_points.Clear();
}
this.message.Text = "Search for the outlined item";
}
During this end mapping process, a path object is created, a click event attached, and that object is added to the children of the canvas.
code to get this path added to the canvas, by the way, if you download the sample code, this is line 509 in page.xaml file.
private void createPolygonPath(string dataline, string shapeName, Color border)
{
//to get this I used code from CreateWPFShape. I also brought up Blend to
//help me with the Xaml for the path, expecially fill and opacity.
//also, in my diagram maker is code which created path geometries programatically
//this came from scribbler.
//
//extract the point array from this dataline. remove markup from the dataline.
dataline = dataline.ToLower();
int ilen = dataline.IndexOf("coords=");
if (ilen < 7)
return;
dataline = dataline.Substring(ilen + 7);
ilen = dataline.IndexOf("href");
if (ilen < 1)
return;
dataline = dataline.Substring(0,ilen);
dataline = dataline.Replace("\"", "");
//message.Text = dataline; //for debugging.
string[] pointlist = dataline.Split(','); //split the dataline on commas into an array.
if (pointlist.Count() < 2)
return;
// Create a new geometry.
PathGeometry geometry = new PathGeometry();
// Create a new path figure.
PathFigure figure = new PathFigure();
figure.Segments = new PathSegmentCollection();
// Add figures to the geometry.
for (int i = 0; i < pointlist.Count(); i++)
{
// Determine the starting index and the end index
// into the points array that defines the figure.
int ptx = -1;
int.TryParse( pointlist[i], out ptx);
int pty = -1;
if ( pointlist.Count() > 1 && i != (pointlist.Count() - 1) )
int.TryParse( pointlist[i + 1], out pty);
else
int.TryParse( pointlist[ pointlist.Count()-1 ], out pty);
System.Windows.Point pt = new Point( ptx, pty);
if (i == 0)
figure.StartPoint = pt;
else
{
LineSegment linesegment1 = new LineSegment();
linesegment1.Point = pt;
figure.Segments.Add(linesegment1);
}
i++; //move to the next x
}
if (geometry.Figures == null)
{
PathFigureCollection pathFigures = new PathFigureCollection();
pathFigures.Add(figure);
geometry.Figures = pathFigures;
}
else
{
// Add the new figure to the geometry.
geometry.Figures.Add(figure);
}
// Add the geometry to a new Path and set path properties.
System.Windows.Shapes.Path path = new System.Windows.Shapes.Path();
path.Data = geometry;
path.SetValue(Canvas.NameProperty, shapeName);
SolidColorBrush brw = new SolidColorBrush(Colors.White);
path.Fill = brw;
path.Opacity = .40;
SolidColorBrush brb = new SolidColorBrush( border );
path.Stroke = brb;
path.MouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler(editItemClick);
LayoutRoot.Children.Add(path);
}
Happy SILVERLIGHT!