I am creating an application just like a paint in WPF, and I want to add zoom functionality to it. I am taking canvas as a parent and writable bitmap on it as child on which I draw. When the size of the canvas is small, I am drawing on writable bitmap smoothly, but when the size of the canvas is large, and zoom it, canvas size will be large, problem occur to draw on this large area. So I want to find the visible region of the canvas so that I can draw on it smoothly. Please give me a source code to find the visible region of the canvas.
开发者_Python百科I have create this application:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Windows.Interop;
namespace MapDesigner.Controls
{
class MapCanvas : Canvas
{
#region Routed Events
public static readonly RoutedEvent SelectedColorChangeEvent = EventManager.RegisterRoutedEvent(
"SelectedColorChange", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ucToolBox));
public event RoutedEventHandler SelectedColorChange
{
add { AddHandler(SelectedColorChangeEvent, value); }
remove { RemoveHandler(SelectedColorChangeEvent, value); }
}
#endregion
#region Enums
public enum Tool
{
Pencil,
FloodFill,
Eraser,
RectSelect,
Brush,
Part
}
#endregion
WriteableBitmap _wBMP;
Image _dispImg = new Image();
ScaleTransform st = new ScaleTransform();
int canvasHeight, canvasWidth;
double zoomLevel = 1;
Border brdGrid = new Border();
Color cellColor = Colors.Black;
Tool currentTool = Tool.Pencil;
int[,] array;
bool drawing = false;
bool showGrids = true;
public TextBlock tbPos;
public Tool CurrentTool
{
get
{
return currentTool;
}
set
{
currentTool = value;
}
}
public Color CellColor
{
get
{
return cellColor;
}
set
{
cellColor = value;
}
}
public bool GridsVisible
{
get
{
return showGrids;
}
set
{
showGrids = value;
}
}
public MapCanvas()
{
this.Children.Clear();
this.Children.Add(_dispImg);
//st.ScaleX = 1;
//st.ScaleY = 1;
// this.LayoutTransform = st;
}
void Refresh()
{
//canvas = new MapCanvas();
this.Children.Clear();
this.Children.Add(_dispImg);
st.ScaleX = 1;
st.ScaleY = 1;
this.Height = 0;
this.Width = 0;
zoomLevel = 1;
drawing = false;
}
public void LoadBMP(Uri bmpUri)
{
Refresh();
BitmapImage bmi = new BitmapImage(bmpUri);
_wBMP = new WriteableBitmap(bmi);
_dispImg.Source = _wBMP;
this.Height = bmi.Height;
this.Width = bmi.Width;
ShowGrids();
}
public void CreateBMP(int width, int height)
{
Refresh();
_wBMP = new WriteableBitmap(width, height, 96, 96, PixelFormats.Bgr32, BitmapPalettes.WebPalette);
_wBMP.setPixel(Colors.White);
_dispImg.Source = _wBMP;
this.Height = height;
this.Width = width;
ShowGrids();
}
public void CreateNewDesign(Size mapSize)
{
Refresh();
_wBMP = new WriteableBitmap((int)mapSize.Width, (int)mapSize.Width, 96, 96, PixelFormats.Bgr32, BitmapPalettes.WebPalette);
_wBMP.setPixel(Colors.White);
_dispImg.Source = _wBMP;
array = new int[(_wBMP.PixelHeight + 1), (_wBMP.PixelWidth + 1)];
canvasWidth = (int)mapSize.Width;
canvasHeight = (int)mapSize.Height;
this.Height = mapSize.Height;
this.Width = mapSize.Width;
ShowGrids();
}
void ShowGrids()
{
return;
double width = 1;// _tileWidth + _tileMargin;
double height = 1;// _tileHeight + _tileMargin;
double numTileToAccumulate = 16;
Polyline gridCell = new Polyline();
gridCell.Margin = new Thickness(.5);
gridCell.Stroke = Brushes.LightBlue;
gridCell.StrokeThickness = 0.1;
gridCell.Points = new PointCollection(new Point[] { new Point(0, height-0.1),
new Point(width-0.1, height-0.1), new Point(width-0.1, 0) });
VisualBrush gridLines = new VisualBrush(gridCell);
gridLines.TileMode = TileMode.Tile;
gridLines.Viewport = new Rect(0, 0, 1.0 / numTileToAccumulate, 1.0 / numTileToAccumulate);
gridLines.AlignmentX = AlignmentX.Center;
gridLines.AlignmentY = AlignmentY.Center;
VisualBrush outerVB = new VisualBrush();
Rectangle outerRect = new Rectangle();
outerRect.Width = 10.0; //can be any size
outerRect.Height = 10.0;
outerRect.Fill = gridLines;
outerVB.Visual = outerRect;
outerVB.Viewport = new Rect(0, 0,
width * numTileToAccumulate, height * numTileToAccumulate);
outerVB.ViewportUnits = BrushMappingMode.Absolute;
outerVB.TileMode = TileMode.Tile;
this.Children.Remove(brdGrid);
brdGrid = new Border();
brdGrid.Height = this.Height;
brdGrid.Width = this.Width;
brdGrid.Background = outerVB;
this.Children.Add(brdGrid);
}
protected override void OnMouseMove(System.Windows.Input.MouseEventArgs e)
{
base.OnMouseMove(e);
tbPos.Text = (_wBMP.PixelWidth / zoomLevel).ToString() + "," + (_wBMP.PixelHeight / zoomLevel).ToString() + " | " + Math.Ceiling((((Point)e.GetPosition(this)).X) / zoomLevel).ToString() + "," + Math.Ceiling((((Point)e.GetPosition(this)).Y / zoomLevel)).ToString();
if (e.LeftButton == System.Windows.Input.MouseButtonState.Pressed)
{
Point pos = e.GetPosition(this);
int xPos = (int)Math.Ceiling((pos.X) / zoomLevel);
int yPos = (int)Math.Ceiling((pos.Y) / zoomLevel);
int xDraw = (int)Math.Ceiling(pos.X);
int yDraw = (int)Math.Ceiling(pos.Y);
array[xPos, yPos] = 1;
drawing = true;
SetPixelsFromArray((int)zoomLevel);
//for (int i = 0; i < zoomLevel; i++)
//{
// for (int j = 0; j < zoomLevel; j++)
// {
// _wBMP.setPixel(xDraw, yDraw, cellColor);
// _dispImg.Source = _wBMP;
// }
//}
//_wBMP.setPixel(xPos, yPos, cellColor);
//_wBMP.setPixel((int)pos.X, (int)pos.Y, cellColor);
//_dispImg.Source = _wBMP;
}
}
private void SetPixelsFromArray(int ZoomLevel)
{
for (int i = 1; i < _wBMP.PixelWidth / ZoomLevel; i++)
{
for (int j = 1; j < _wBMP.PixelHeight / ZoomLevel; j++)
{
if (array[i, j] == 1)
{
for (int k = 0; k < ZoomLevel; k++)
{
for (int l = 0; l < ZoomLevel; l++)
{
_wBMP.setPixel((int)(i * ZoomLevel + k), (int)(j * ZoomLevel + l), cellColor);
_dispImg.Source = _wBMP;
}
}
}
}
}
}
protected override void OnMouseUp(System.Windows.Input.MouseButtonEventArgs e)
{
//double d= this.ActualHeight;
//Double t =(double) this.GetValue(Canvas.TopProperty);
//double i = Convert.ToDouble(top);
getScreenRect();
if (e.ChangedButton == System.Windows.Input.MouseButton.Right)
{
if (cellColor == Colors.Black)
{
cellColor = Colors.Red;
}
else
{
cellColor = Colors.Black;
}
}
else if (e.ChangedButton == System.Windows.Input.MouseButton.Left)
{
Point pos = e.GetPosition(this);
int xPos = (int)Math.Ceiling((pos.X) / zoomLevel);
int yPos = (int)Math.Ceiling((pos.Y) / zoomLevel);
array[xPos, yPos] = 1;
drawing = true;
SetPixelsFromArray((int)zoomLevel);
//_wBMP.setPixel((int)pos.X, (int)pos.Y, cellColor);
//_dispImg.Source = _wBMP;
}
}
private void getScreenRect()
{
Visual _rootVisual = HwndSource.FromVisual(this).RootVisual;
GeneralTransform transformToRoot = this.TransformToAncestor(_rootVisual);
Rect screenRect = new Rect(transformToRoot.Transform(new Point(0, 0)), transformToRoot.Transform(new Point(this.ActualWidth, this.ActualHeight)));
DependencyObject parent = VisualTreeHelper.GetParent(this);
while (parent != null)
{
Visual visual = parent as Visual;
System.Windows.Controls.Control control = parent as System.Windows.Controls.Control;
if (visual != null && control != null)
{
transformToRoot = visual.TransformToAncestor(_rootVisual);
Point pointAncestorTopLeft = transformToRoot.Transform(new Point(0, 0));
Point pointAncestorBottomRight = transformToRoot.Transform(new Point(control.ActualWidth, control.ActualHeight));
Rect ancestorRect = new Rect(pointAncestorTopLeft, pointAncestorBottomRight);
screenRect.Intersect(ancestorRect);
}
parent = VisualTreeHelper.GetParent(parent);
//}
// at this point screenRect is the bounding rectangle for the visible portion of "this" element
}
// return screenRect;
}
protected override void OnMouseWheel(System.Windows.Input.MouseWheelEventArgs e)
{
base.OnMouseWheel(e);
if (e.Delta > 0)
{
zoomLevel *= 2;
}
else
{
zoomLevel /= 2;
}
if (zoomLevel > 8)
{
zoomLevel = 8;
}
if (zoomLevel <= 1)
{
zoomLevel = 1;
// brdGrid.Visibility = Visibility.Collapsed;
}
else
{
//brdGrid.Visibility = Visibility.Visible;
}
_wBMP = new WriteableBitmap((int)zoomLevel * canvasWidth, (int)zoomLevel * canvasHeight, 96, 96, PixelFormats.Bgr32, BitmapPalettes.WebPalette);
_wBMP.setPixel(Colors.White);
this.Width = zoomLevel * canvasWidth;
this.Height = zoomLevel * canvasHeight;
if (drawing == true)
{
SetPixelsFromArray((int)zoomLevel);
}
//this.InvalidateVisual();
}
internal bool SaveAsBMP(string fileName)
{
return true;
}
}
public static class bitmapextensions
{
public static void setPixel(this WriteableBitmap wbm, Color c)
{
if (!wbm.Format.Equals(PixelFormats.Bgr32))
return;
wbm.Lock();
IntPtr buff = wbm.BackBuffer;
int Stride = wbm.BackBufferStride;
int x = 0;
int y = 0;
for (x = 0; x < wbm.PixelWidth; x++)
{
for (y = 0; y < wbm.PixelHeight; y++)
{
unsafe
{
byte* pbuff = (byte*)buff.ToPointer();
int loc = y * Stride + x * 4;
pbuff[loc] = c.B;
pbuff[loc + 1] = c.G;
pbuff[loc + 2] = c.R;
//pbuff[loc + 3] = c.A;
}
}
}
wbm.AddDirtyRect(new Int32Rect(0, 0, x, y));
wbm.Unlock();
}
public static void setPixel(this WriteableBitmap wbm, int x, int y, Color c)
{
if (y > wbm.PixelHeight - 1 || x > wbm.PixelWidth - 1)
return;
if (y < 0 || x < 0)
return;
if (!wbm.Format.Equals(PixelFormats.Bgr32))
return;
wbm.Lock();
IntPtr buff = wbm.BackBuffer;
int Stride = wbm.BackBufferStride;
unsafe
{
byte* pbuff = (byte*)buff.ToPointer();
int loc = y * Stride + x * 4;
pbuff[loc] = c.B;
pbuff[loc + 1] = c.G;
pbuff[loc + 2] = c.R;
//pbuff[loc + 3] = c.A;
}
wbm.AddDirtyRect(new Int32Rect(x, y, 1, 1));
wbm.Unlock();
}
public static Color getPixel(this WriteableBitmap wbm, int x, int y)
{
if (y > wbm.PixelHeight - 1 || x > wbm.PixelWidth - 1)
return Color.FromArgb(0, 0, 0, 0);
if (y < 0 || x < 0)
return Color.FromArgb(0, 0, 0, 0);
if (!wbm.Format.Equals(PixelFormats.Bgr32))
return Color.FromArgb(0, 0, 0, 0);
IntPtr buff = wbm.BackBuffer;
int Stride = wbm.BackBufferStride;
Color c;
unsafe
{
byte* pbuff = (byte*)buff.ToPointer();
int loc = y * Stride + x * 4;
c = Color.FromArgb(pbuff[loc + 3], pbuff[loc + 2], pbuff[loc + 1], pbuff[loc]);
}
return c;
}
}
}
You should implement IScrollInfo
on your canvas (or actually, create a custom Panel that inherits from Canvas and implements IScrollInfo).
That interface holds all that is relevant to your situation:
http://msdn.microsoft.com/en-us/library/system.windows.controls.primitives.iscrollinfo.aspx http://blogs.msdn.com/b/jgoldb/archive/2008/03/08/performant-virtualized-wpf-canvas.aspx
精彩评论