After playing for a while with the January CTP release of Windows Presentation Foundation, formerly known as Avalon, I write a simple application with which you can draw the lines continuously using mouse, the XAML code and corresponding C# code dealing with the interactive logic is listed as follows:
DrawingWindow.xaml:
DrawingWindow.xaml.cs:
One caveat here is that it seems the Canvas element cannot capture any mouse event, for instance MouseDown, MouseUp and MouseMove events, after digging into this problem for a while, I find a workaround by overlapping a transparent StackPanel element named capturePanel on top of the Canvas element, and hook up mouse event handlers with this capturePanel's corresponding mouse events, I can actually capture the mouse events for the Canvas element, and then draw the line in it.
It's simple but quite interesting, please enjoy it!
DrawingWindow.xaml:
<Window x:Class="AvalonPaint.DrawingWindow"
xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005"
Title="AvalonPaint"
Loaded="DrawingWindow_Loaded" Height="400" Width="600">
<Window.Resources>
<DrawingBrush x:Key="backgroundResource"
Viewport="0,0,10,10" ViewportUnits="Absolute" TileMode="Tile">
<DrawingBrush.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="White">
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="0,0,1,1" />
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing Brush="#AAE6E8F6"
Geometry="M 0,0 L 0,1 0.1,1 0.1,0.1 1,0.1 1,0 Z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Canvas Name="drawingBoard" Grid.Column="0" Grid.Row="0" Background="{StaticResource backgroundResource}"/>
<StackPanel Name="capturePanel" Background="Transparent"/>
</Grid>
</Window>
xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005"
Title="AvalonPaint"
Loaded="DrawingWindow_Loaded" Height="400" Width="600">
<Window.Resources>
<DrawingBrush x:Key="backgroundResource"
Viewport="0,0,10,10" ViewportUnits="Absolute" TileMode="Tile">
<DrawingBrush.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="White">
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="0,0,1,1" />
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing Brush="#AAE6E8F6"
Geometry="M 0,0 L 0,1 0.1,1 0.1,0.1 1,0.1 1,0 Z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Canvas Name="drawingBoard" Grid.Column="0" Grid.Row="0" Background="{StaticResource backgroundResource}"/>
<StackPanel Name="capturePanel" Background="Transparent"/>
</Grid>
</Window>
DrawingWindow.xaml.cs:
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace AvalonPaint
{
/// <summary>
/// Interaction logic for DrawingWindow.xaml
/// </summary>
public partial class DrawingWindow : Window
{
private Boolean isDrawing = false;
private Point startPoint;
public DrawingWindow()
{
InitializeComponent();
}
private void DrawingWindow_Loaded(Object sender, RoutedEventArgs e)
{
capturePanel.MouseDown += capturePanel_MouseDown;
capturePanel.MouseMove += capturePanel_MouseMove;
capturePanel.MouseUp += capturePanel_MouseUp;
}
private void capturePanel_MouseDown(Object sender, MouseEventArgs e)
{
isDrawing = true;
startPoint = e.GetPosition(this);
}
private void capturePanel_MouseMove(Object sender, MouseEventArgs e)
{
if (isDrawing && e.LeftButton == MouseButtonState.Pressed)
{
Point endPoint = e.GetPosition(this);
DrawLine(startPoint, endPoint, drawingBoard);
startPoint = endPoint;
}
}
private void capturePanel_MouseUp(Object sender, MouseEventArgs e)
{
startPoint = e.GetPosition(this);
//Disable mouse capture for the current Window element.
Mouse.Capture(this, CaptureMode.None);
isDrawing = false;
}
// Private helper method responsible for drawing lines in the surface of Canvas element.
private void DrawLine(Point from, Point to, Canvas targetCanvas)
{
Line line = new Line();
line.StrokeEndLineCap = PenLineCap.Round;
line.StrokeStartLineCap = PenLineCap.Round;
line.Stroke = Brushes.Red;
line.StrokeThickness = 3.0;
line.X1 = from.X;
line.Y1 = from.Y;
line.X2 = to.X;
line.Y2 = to.Y;
Canvas.SetLeft(targetCanvas, from.X);
Canvas.SetTop(targetCanvas, from.Y);
targetCanvas.Children.Add(line);
}
}
}
using System.Windows;
using System.Windows.Input;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace AvalonPaint
{
/// <summary>
/// Interaction logic for DrawingWindow.xaml
/// </summary>
public partial class DrawingWindow : Window
{
private Boolean isDrawing = false;
private Point startPoint;
public DrawingWindow()
{
InitializeComponent();
}
private void DrawingWindow_Loaded(Object sender, RoutedEventArgs e)
{
capturePanel.MouseDown += capturePanel_MouseDown;
capturePanel.MouseMove += capturePanel_MouseMove;
capturePanel.MouseUp += capturePanel_MouseUp;
}
private void capturePanel_MouseDown(Object sender, MouseEventArgs e)
{
isDrawing = true;
startPoint = e.GetPosition(this);
}
private void capturePanel_MouseMove(Object sender, MouseEventArgs e)
{
if (isDrawing && e.LeftButton == MouseButtonState.Pressed)
{
Point endPoint = e.GetPosition(this);
DrawLine(startPoint, endPoint, drawingBoard);
startPoint = endPoint;
}
}
private void capturePanel_MouseUp(Object sender, MouseEventArgs e)
{
startPoint = e.GetPosition(this);
//Disable mouse capture for the current Window element.
Mouse.Capture(this, CaptureMode.None);
isDrawing = false;
}
// Private helper method responsible for drawing lines in the surface of Canvas element.
private void DrawLine(Point from, Point to, Canvas targetCanvas)
{
Line line = new Line();
line.StrokeEndLineCap = PenLineCap.Round;
line.StrokeStartLineCap = PenLineCap.Round;
line.Stroke = Brushes.Red;
line.StrokeThickness = 3.0;
line.X1 = from.X;
line.Y1 = from.Y;
line.X2 = to.X;
line.Y2 = to.Y;
Canvas.SetLeft(targetCanvas, from.X);
Canvas.SetTop(targetCanvas, from.Y);
targetCanvas.Children.Add(line);
}
}
}
One caveat here is that it seems the Canvas element cannot capture any mouse event, for instance MouseDown, MouseUp and MouseMove events, after digging into this problem for a while, I find a workaround by overlapping a transparent StackPanel element named capturePanel on top of the Canvas element, and hook up mouse event handlers with this capturePanel's corresponding mouse events, I can actually capture the mouse events for the Canvas element, and then draw the line in it.
It's simple but quite interesting, please enjoy it!