I have a canvas in grid. On the mousemove event of canvas i am trying to translate the canvas. It works fine. However my canvas doesn't occupy the full space in the grid. What changes do i need to make in this program so that the canvas occupies the full space.
This is my xaml :-
<UserControl x:Class="SilverlightTestCanvasDemo.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<Canvas x:Name="canvas" Margin="0" Background="Red">
<TextBlock Canvas.Left="84" TextWrapping="Wrap" Text="This is some text to test whether screen is moving" Canvas.Top="99" Height="84" Width="196" FontSize="18.667" FontFamily="Cambria"/>
</Canvas>
</Grid>
</UserControl>
This is the code :-
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace SilverlightTestCanvasDemo
{
public partial class MainPage : UserControl
{
private bool _isDown = false;
private Point _lastPoint;
public MainPage()
{
InitializeComponent();
this.Loaded += MainPage_Loaded;
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
canvas.MouseLeftButtonDown += canvas_MouseLeftButtonDown;
canvas.MouseLeftButtonUp += canvas_MouseLeftButtonUp;
canvas.MouseMove += canvas_MouseMove;
}
void canvas_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
if (_isDown)
{
Point point = e.GetPosition(canvas);
double deltaX = point.X - _lastPoint.X;
double deltaY = point.Y - _lastPoint.Y;
CompositeTransform transform = null;
if (!(canvas.RenderTransform is CompositeTransform))
{
transform = new CompositeTransform();
canvas.RenderTransform = transform;
}
else
{
transform = canvas.RenderTransform as CompositeTransform;
}
transform.TranslateX += deltaX;
transform.TranslateY += deltaY;
//canvas.Height += deltaY;
//canvas.Width += deltaX;
_lastPoint = e.GetPosition(canvas);
}
}
void canvas_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
_isDown = false;
}
void canvas_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
_isDown = true;
_lastPoint = e.GetPosition(canvas);
}
}
}
Thanks in advance :)
Try this:-
<Grid x:Name="LayoutRoot">
<Canvas x:Name="canvas" Margin="0" Background="AliceBlue">
<Canvas>
<TextBlock Canvas.Left="84" TextWrapping="Wrap" Text="This is some text to test whether screen is moving" Canvas.Top="99" Height="84" Width="196" FontSize="18.667" FontFamily="Cambria"/>
</Canvas>
</Canvas>
</Grid>
and tweak the mouse move code behind to this:-
void canvas_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
if (_isDown)
{
Point point = e.GetPosition(canvas);
double deltaX = point.X - _lastPoint.X;
double deltaY = point.Y - _lastPoint.Y;
CompositeTransform transform = null;
if (!(canvas.Children[0].RenderTransform is CompositeTransform))
{
transform = new CompositeTransform();
canvas.Children[0].RenderTransform = transform;
}
else
{
transform = canvas.Children[0].RenderTransform as CompositeTransform;
}
transform.TranslateX += deltaX;
transform.TranslateY += deltaY;
_lastPoint = e.GetPosition(canvas);
}
}
What's happening here is a second inner Canvas is being used as a caddy to hold the set of actual children. Now you need only transform this inner canvas to move all the content about.
Related
I am trying to make a simple 2D Game in WPF, and I've come across a problem I can't solve.
Let's say I have a player on a 700x700 Canvas, but my MainWindow's Width and Height are set to 400.
I want to be able to have a camera like feature, that follows a rectangle object on the canvas (this object symbolises the player) and shows the corresponding portion of the canvas whenever the player moves.
In theory how could I implement a feature like this?
Here's a rough sample of how to do that with a ScrollViewer. Use the arrow keys to move the player around while keeping it in the view of the "camera". The canvas' background is set to a radial-brush, to see the camera moving.
MainWindow.xaml
<Window x:Class="WpfApp6.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow"
Background="#222"
Loaded="Window_Loaded"
SizeToContent="WidthAndHeight"
PreviewKeyDown="Window_PreviewKeyDown">
<Grid>
<ScrollViewer x:Name="CanvasViewer"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden">
<Canvas x:Name="Canvas"
IsHitTestVisible="False">
<Canvas.Background>
<RadialGradientBrush>
<GradientStop Offset="0"
Color="Orange" />
<GradientStop Offset="1"
Color="Blue" />
</RadialGradientBrush>
</Canvas.Background>
</Canvas>
</ScrollViewer>
</Grid>
</Window>
MainWindow.xaml.cs
public partial class MainWindow : Window
{
double _playerSize;
Rectangle _playerRect;
Vector _playerPosition;
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
InitializeSizes();
InitializePlayerRect();
}
#region initialize
private void InitializeSizes()
{
_playerSize = 50;
Canvas.Width = 700;
Canvas.Height = 700;
CanvasViewer.Width = 400;
CanvasViewer.Height = 400;
}
private void InitializePlayerRect()
{
_playerRect = new Rectangle
{
Fill = Brushes.Lime,
Width = _playerSize,
Height = _playerSize,
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Top
};
Canvas.Children.Add(_playerRect);
}
#endregion
#region move player
private void Window_PreviewKeyDown(object sender, KeyEventArgs e)
{
switch (e.Key)
{
case Key.Left: MovePlayerLeft(); break;
case Key.Up: MovePlayerUp(); break;
case Key.Right: MovePlayerRight(); break;
case Key.Down: MovePlayerDown(); break;
}
}
private void MovePlayerLeft()
{
var newX = _playerPosition.X - _playerSize;
_playerPosition.X = Math.Max(0, newX);
UpdatePlayerPositionAndCamera();
}
private void MovePlayerUp()
{
var newY = _playerPosition.Y - _playerSize;
_playerPosition.Y = Math.Max(0, newY);
UpdatePlayerPositionAndCamera();
}
private void MovePlayerRight()
{
var newX = _playerPosition.X + _playerSize;
_playerPosition.X = Math.Min(Canvas.Width - _playerSize, newX);
UpdatePlayerPositionAndCamera();
}
private void MovePlayerDown()
{
var newY = _playerPosition.Y + _playerSize;
_playerPosition.Y = Math.Min(Canvas.Height - _playerSize, newY);
UpdatePlayerPositionAndCamera();
}
#endregion
#region update player and camera
private void UpdatePlayerPositionAndCamera()
{
UpdatePlayerPosition();
UpdateCamera();
}
private void UpdatePlayerPosition()
{
// move the playerRect to it's new position
_playerRect.Margin = new Thickness(_playerPosition.X, _playerPosition.Y, 0, 0);
}
private void UpdateCamera()
{
// calculate offset of scrollViewer, relative to actual position of the player
var offsetX = _playerPosition.X / 2;
var offsetY = _playerPosition.Y / 2;
// move the "camera"
CanvasViewer.ScrollToHorizontalOffset(offsetX);
CanvasViewer.ScrollToVerticalOffset(offsetY);
}
#endregion
}
WPF isn't really the right technology for games, you're much better off using something like MonoGame.
To answer your question, though, you can wrap your canvas in a ScrollViewer:
<ScrollViewer x:Name="theScrollView" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" CanContentScroll="True">
<Canvas x:Name="theCanvas" Width="5000" Height="5000" />
</ScrollViewer>
Then in code you scroll the view to whatever position your camera is at:
theScrollView.ScrollToHorizontalOffset(100);
I am new to WPF I want to scale ellipse by selecting its stroke. I have set IsManipulationEnabled=true but an event not triggering. Below is my code
<Path Stretch="Fill" Stroke="Black" ManipulationDelta="Path_ManipulationDelta"
IsManipulationEnabled="True" StrokeThickness="4">
<Path.Data>
<EllipseGeometry Center="0,0" RadiusX="200" RadiusY="200"/>
</Path.Data>
</Path>
Please Help.enter image description here
Here is some code that may give you some ideas:
In this sample, I'm using some basic mouse events MouseDown, MouseMove, and MouseUp so that I can detect when a user clicks on the Path, and when they start to drag the mouse.
XAML
<Window x:Class="WpfApp4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp4"
Title="MainWindow"
Width="800"
Height="450"
UseLayoutRounding="True">
<Grid>
<Canvas x:Name="Canvas">
<Path x:Name="CirclePath"
MouseDown="OnMouseDown"
MouseMove="OnMouseMove"
MouseUp="OnMouseUp"
Stretch="Fill"
Stroke="Black"
StrokeThickness="4">
<Path.Data>
<EllipseGeometry x:Name="EllipseGeometry"
Center="0,0"
RadiusX="100"
RadiusY="100" />
</Path.Data>
</Path>
</Canvas>
</Grid>
</Window>
In the OnMouseDown handler, I check to see if the left mouse button is down and then I capture the mouse and get the position of the mouse relative to the Canvas.
Next, in the OnMouseMove handler, if the left button is still down - the user is dragging - I get the new mouse position and calculate the offset based on the old mouse position. Then I update the EllipseGeometry to reflect the mouse offset.
Finally, in the OnMouseUp handler, I release the mouse capture.
Code-Behind
using System.Windows;
using System.Windows.Input;
namespace WpfApp4
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private Point oldMousePosition;
public MainWindow()
{
InitializeComponent();
}
private void OnMouseDown(object sender, MouseButtonEventArgs e)
{
if(e.ChangedButton != MouseButton.Left) return;
Mouse.Capture(CirclePath);
oldMousePosition = e.GetPosition(Canvas);
}
private void OnMouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton != MouseButtonState.Pressed) return;
var newMousePosition = e.GetPosition(Canvas);
var offset = newMousePosition - oldMousePosition;
EllipseGeometry.RadiusX += offset.X / 2;
EllipseGeometry.RadiusY += offset.Y / 2;
oldMousePosition = newMousePosition;
}
private void OnMouseUp(object sender, MouseButtonEventArgs e)
{
Mouse.Capture(null);
}
}
}
I hope this helps.
XAML
XAML
<Window x:Class="WidgetWpf.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WidgetWpf"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Viewbox>
<Grid Name="MainGrid">
<Ellipse x:Name="DottedCircle" Width="200" Height="200" Stroke="White" StrokeThickness="2" Opacity="0.90" StrokeDashArray="4 4"
MouseDown="DottedCircle_MouseDown"
MouseMove="DottedCircle_MouseMove"
MouseUp="DottedCircle_MouseUp"
MouseEnter="DottedCircle_MouseEnter"
MouseLeave="DottedCircle_MouseLeave"
/>
</Grid>
</Viewbox>
</Window>
//Here is my code behind
public partial class MainWindow : Window
{
#region Variables
MatrixTransform transform;
Point OldMousePosition;
Point NewMousePosition;
double[] Dimensions = new double[2];
Rect rect = new Rect();
bool IsResizeMode;
bool IsDragAndDropMode;
#endregion
public MainWindow()
{
InitializeComponent();
}
private void DottedCircle_MouseDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton != MouseButton.Left) return;
Mouse.Capture(DottedCircle);
OldMousePosition = e.GetPosition(MainGrid);
}
private void DottedCircle_MouseMove(object sender, MouseEventArgs e)
{
DottedCircle.ToolTip = e.GetPosition(MainGrid);
if (e.LeftButton != MouseButtonState.Pressed) return;
var NewMousePosition = e.GetPosition(MainGrid);
var offset = NewMousePosition-OldMousePosition;
#region working by co-ordinate
//get center of grid
double dicisionPoint=0.0 ;
double CP_X = MainGrid.ActualWidth / 2;
double CP_Y = MainGrid.ActualHeight / 2;
//1 st co-ordinate
if(NewMousePosition.X>CP_X && NewMousePosition.Y<CP_Y)
{
dicisionPoint = offset.X;
}
//2nd cordinate
else if (NewMousePosition.X < CP_X && NewMousePosition.Y < CP_Y)
{
dicisionPoint = -offset.X;
}
else if (NewMousePosition.X < CP_X && NewMousePosition.Y > CP_Y)
{
dicisionPoint = offset.Y;
}
else if (NewMousePosition.X > CP_X && NewMousePosition.Y > CP_Y)
{
dicisionPoint = offset.Y;
}
if (DottedCircle.Width+ dicisionPoint < InnerCircle.Width)
{
DottedCircle.Fill = new SolidColorBrush(Colors.Transparent);
DottedCircle.Width += dicisionPoint;
DottedCircle.Height += dicisionPoint;
}
else if (DottedCircle.Width+ dicisionPoint>= InnerCircle.Width) { DottedCircle.Fill = new SolidColorBrush(Colors.Red); }
#endregion
OldMousePosition = NewMousePosition;
DottedCircle.ToolTip = offset.X+ "__" + offset.Y;
}
private void DottedCircle_MouseUp(object sender, MouseButtonEventArgs e)
{
Mouse.Capture(null);
DottedCircle.Style = null;
}
private void DottedCircle_MouseEnter(object sender, MouseEventArgs e)
{
DottedCircle.Stroke = new SolidColorBrush( Colors.Blue);
DottedCircle.Style = (Style)Application.Current.Resources["DiffPathStyle"];
}
private void DottedCircle_MouseLeave(object sender, MouseEventArgs e)
{
DottedCircle.Stroke = new SolidColorBrush(Colors.White);
DottedCircle.Style = null;
}
}
I have the TextBox in silverlight 4 in 2 modes: insert and overwrite.
Can anyone help me? If I press the overwrite mode, I want to make the caret blinking size bigger.
I have used to CaretBrush, but it can change the color of caret only.
Many thanks if you have suggestion or the sample code.
At the time looking someone can help, I tried this solution for myself, It's abit complex, but I hope someone can use my code and customize yourself. Someone can get this code for trying if you have this case
The MainPage.xaml code:
<UserControl x:Class="SilverlightApplication1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.micros`enter code here`oft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid Name="LayoutRoot">
<Canvas x:Name="canvasDataView" VerticalAlignment="Top" Background="White" HorizontalAlignment="Left">
<TextBox HorizontalAlignment="Left" Canvas.Left="50" VerticalAlignment="Top" x:Name="positionTextBox" Canvas.ZIndex="2" Text="position" Canvas.Top="25" Visibility="Collapsed" Width="100" Height="25"></TextBox>
<TextBox x:Name="textBox1" Text="asdfasdfasd asda asdf as adfasdfads adf asdf adfasdf" SelectionForeground="AliceBlue" KeyDown="textBox1_KeyDown" KeyUp="textBox1_KeyUp" TextWrapping="NoWrap" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Visible" AcceptsReturn="True" Height="25" Width="500" />
<TextBox x:Name="shadowTextBox" Canvas.ZIndex="-1" Canvas.Left="350" Height="20" Width="20" HorizontalScrollBarVisibility="Visible" AcceptsReturn="True" VerticalScrollBarVisibility="Visible" Visibility="Visible" TextWrapping="NoWrap"/>
</Canvas>
</Grid>
</UserControl>
The code behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Expression.Interactivity;
using System.Windows.Controls.Primitives;
namespace SilverlightApplication1
{
public partial class MainPage : UserControl
{
Duration duration = new Duration(TimeSpan.FromSeconds(0.5));
Storyboard storybroad = new Storyboard();
Rectangle myRectangle = null;
ScrollViewer sv;
public MainPage()
{
InitializeComponent();
textBox1.KeyUp += new KeyEventHandler(textBox1_KeyUp);
textBox1.TextChanged += new TextChangedEventHandler(textBox1_TextChanged);
textBox1.CaretBrush = new SolidColorBrush(Colors.Transparent);
}
void textBox1_TextChanged(object sender, TextChangedEventArgs e)
{
shadowTextBox.Text = textBox1.Text;
shadowTextBox.SelectionStart = textBox1.SelectionStart;
Point p = getCaretPosition(textBox1, shadowTextBox);
MoveCaret(p);
}
void textBox1_KeyDown(object sender, KeyEventArgs e)
{
shadowTextBox.Text = textBox1.Text;
shadowTextBox.SelectionStart = textBox1.SelectionStart;
}
void textBox1_KeyUp(object sender, KeyEventArgs e)
{
shadowTextBox.Text = textBox1.Text;
shadowTextBox.SelectionStart = textBox1.SelectionStart;
// get caret position
Point p = getCaretPosition(textBox1,shadowTextBox);
MoveCaret(p);
}
private Point getCaretPosition(TextBox textBox, TextBox shadowTextBox)
{
Point _point = new Point();
// get main textbox's scroll offset, if any
getScrollBar(textBox);
double initVerticalOffset = sv.VerticalOffset;
double initHorizontalOffset = sv.HorizontalOffset;
// get shadow box scroll offset
getScrollBar(shadowTextBox);
double vOffset = sv.VerticalOffset;
double hOffset = sv.HorizontalOffset;
// caret position is scroll offset of shadaw minus scroll offset of main (if any)
_point.Y = vOffset - initVerticalOffset;
_point.X = hOffset - initHorizontalOffset;
return _point;
}
private void getScrollBar(UIElement src)
{
// walk visual tree for this object until we get the scrollviewer
if (src.GetType().ToString() == "System.Windows.Controls.ScrollViewer")
sv = src as ScrollViewer;
else
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(src); i++)
{
UIElement elem = (UIElement)VisualTreeHelper.GetChild(src, i);
getScrollBar(elem);
}
}
}
void MoveCaret(Point point)
{
if (storybroad == null)
storybroad = new Storyboard();
storybroad.Stop();
if (point != new Point(0, 0))
{
if (myRectangle != null && canvasDataView.Children.Contains(myRectangle))
{
canvasDataView.Children.Remove(myRectangle);
}
myRectangle = new Rectangle();
myRectangle.SetValue(Canvas.TopProperty, point.Y);
myRectangle.SetValue(Canvas.LeftProperty, point.X);
myRectangle.Width = 5;
myRectangle.Height = 16;
myRectangle.Fill = new SolidColorBrush();
storybroad.BeginTime = new TimeSpan(0, 0, 0, 0, 0);
storybroad.RepeatBehavior = RepeatBehavior.Forever;
ColorAnimation color = new ColorAnimation();
canvasDataView.Children.Add(myRectangle);
color.From = Colors.Transparent;
color.To = Colors.Green;
color.Duration = duration;
storybroad.Children.Add(color);
Storyboard.SetTarget(color, myRectangle);
Storyboard.SetTargetProperty(color, new PropertyPath("(Fill).(SolidColorBrush.Color)"));
storybroad.Begin();
}
}
}
}
I have a project that uses a System.Windows.Controls.Primatives.Popup to drag a 'tooltip' like control along with a mouse.
Whenever the drag crosses a horizontal line the popup 'wraps' to the bottom of the screen - despite having sane values for the VerticalOffset. The point at which this wrapping occurs appears to be tied to the HEIGHT of the window, but not it's position.
Here's the code from the sandbox project I have created that also exhibits the same behavior:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.MainGrid.MouseDown += Grid_MouseDown;
this.MainGrid.MouseUp += Grid_MouseUp;
this.MainGrid.MouseMove += (s, e) => { if (this.Popup.IsOpen) { Popup_Drag(s, e); } };
this.Popup.MouseMove += Popup_Drag;
}
private void Popup_Drag(object sender, MouseEventArgs e)
{
Popup.HorizontalOffset = e.GetPosition(this.Popup).X;
Popup.VerticalOffset = e.GetPosition(this.Popup).Y;
this.Status_Top.Text = String.Format("Height/Top: {0}/{1} Width/Left: {2}/{3}", this.Height, this.Top, this.Width, this.Left);
this.Status.Text = String.Format("Vertical Offset: {0} Horizontal Offset: {1}", Popup.VerticalOffset, Popup.HorizontalOffset);
}
private void Grid_MouseUp(object sender, MouseButtonEventArgs e)
{
this.Popup.IsOpen = false;
}
private void Grid_MouseDown(object sender, MouseButtonEventArgs e)
{
this.Popup.IsOpen = true;
Popup_Drag(sender, e);
}
}
And the Window XAML:
<Window x:Class="WpfSandbox.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid x:Name="MainGrid" Background="Purple">
<TextBlock x:Name="Status_Top"></TextBlock>
<Popup x:Name="Popup" Cursor="Hand" HorizontalAlignment="Left"
VerticalAlignment="Bottom" IsOpen="True">
<TextBlock Background="Blue" Foreground="White">
<TextBlock x:Name="Status">TEXT</TextBlock></TextBlock>
</Popup>
</Grid>
</Window>
I was able to fix this by adding Placement="RelativePoint" to the Popup attributes. Apparently this is the default in Silverlight, but not WPF.
Is there anyone who experienced with the scrollviewer component in WPF? I have a basic selection zoom, and the problem is that it does not scroll to the right place.
Output, trying to zoom the flower:
Actually, the RectangleZoom (see bellow) method scales the picture, but it does not focus it on the specified rectangle, but always in the same position... I believe there is a way to scroll to that position, but till now, any success....
Here is my code:
XAML:
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<ScrollViewer x:Name="scrollViewer"
HorizontalScrollBarVisibility="Auto">
<Canvas Height="200" Name="mainCanvas" Width="400"
MouseLeftButtonDown="mainCanvas_MouseLeftButtonDown"
MouseLeftButtonUp="mainCanvas_MouseLeftButtonUp"
MouseMove="mainCanvas_MouseMove">
<Canvas.Background>
<ImageBrush ImageSource="/WpfApplication3;component/Images/natural-doodle.jpg"/>
</Canvas.Background>
<Canvas.LayoutTransform>
<TransformGroup>
<ScaleTransform x:Name="scaleTransform"/>
</TransformGroup>
</Canvas.LayoutTransform>
</Canvas>
</ScrollViewer>
</Window>
Code behind:
public partial class MainWindow : Window
{
private Point startPoint;
private Point endPoint;
private Shape rubberBand;
public MainWindow()
{
InitializeComponent();
}
private void mainCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (!mainCanvas.IsMouseCaptured)
{
startPoint = e.GetPosition(mainCanvas);
Mouse.Capture(mainCanvas);
}
}
private void mainCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (mainCanvas.IsMouseCaptured)
{
if (rubberBand != null)
{
this.RectangleZoom(
Canvas.GetLeft(rubberBand),
Canvas.GetTop(rubberBand),
rubberBand.Width,
rubberBand.Height);
mainCanvas.Children.Remove(rubberBand);
rubberBand = null;
mainCanvas.ReleaseMouseCapture();
}
}
}
private void mainCanvas_MouseMove(object sender, MouseEventArgs e)
{
if (mainCanvas.IsMouseCaptured)
{
endPoint = e.GetPosition(mainCanvas);
if (rubberBand == null)
{
rubberBand = new Rectangle();
rubberBand.Stroke = Brushes.Red;
rubberBand.StrokeDashArray = new DoubleCollection(new double[] { 4, 2 });
mainCanvas.Children.Add(rubberBand);
}
rubberBand.Width = Math.Abs(startPoint.X - endPoint.X);
rubberBand.Height = Math.Abs(startPoint.Y - endPoint.Y);
double left = Math.Min(startPoint.X, endPoint.X);
double top = Math.Min(startPoint.Y, endPoint.Y);
Canvas.SetLeft(rubberBand, left);
Canvas.SetTop(rubberBand, top);
}
}
private void RectangleZoom(double x, double y, double width, double height)
{
double rWidth = scrollViewer.ViewportWidth / width;
double rHeight = scrollViewer.ViewportHeight / height;
double rZoom = 1.0;
if (rWidth < rHeight)
rZoom = rWidth;
else
rZoom = rHeight;
scaleTransform.ScaleX = rZoom;
scaleTransform.ScaleY = rZoom;
}
}
You got it all but three lines:
Add these to the bottom of your RetangleZoom method:
Point newXY = scaleTransform.Transform(new Point(x, y));
scrollViewer.ScrollToHorizontalOffset(newXY.X);
scrollViewer.ScrollToVerticalOffset(newXY.Y);