Prevent WPF Image in border from panning too far - wpf

I have a WPF Image inside a Border I currently am able to click and drag to pan the image. I want to prevent users from dragging the image off the screen. Perhaps a minimum of 100 pixels should be showing at any border. That is, if a user drags the image all the way to the left, most of the image will disappear, but 100 pixels will still be hanging out toward the left boundary of the border.
Here's my current code for the MouseMove and LeftClick event:
private void img_Box_MouseMove(object sender, MouseEventArgs e)
{
if (!img_Box.IsMouseCaptured) return;
var tt = (TranslateTransform)((TransformGroup)img_Box.RenderTransform).Children.First(tr => tr is TranslateTransform);
Vector v = start - e.GetPosition(img_Border);
tt.X = origin.X - v.X;
tt.Y = origin.Y - v.Y;
}
private void img_Box_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
img_Box.CaptureMouse();
var tt = (TranslateTransform)((TransformGroup)img_Box.RenderTransform).Children.First(tr => tr is TranslateTransform);
start = e.GetPosition(img_Border);
origin = new System.Windows.Point(tt.X, tt.Y);
}
I think I should be able to put a pretty simple condition on that to achieve my desired result, but I can't figure out what the condition should be.

Related

Scroll over datagrid with click drag

I have a datagrid, this is loaded by a xml file... no problem.
I need allow scroll when user drag over all datagrid, or select row and drag up or down to scroll content.
I have de scrollbar but, this app is for touch screen so is more easy drag on datagrid to scroll.
Thanks...
This should do the trick. Handle the Drag event of datagrid and scroll the datagrid programmatically.
// hook up the row events during the loading row event for the datagrid
private void MyDataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
{
e.Row.DragOver += new DragEventHandler(MyRow_DragOver);
e.Row.Drop += new DragEventHandler(MyRow_Drop);
}
private void MyRow_DragOver(object sender, DragEventArgs e)
{
DataGridRow r = (DataGridRow)sender;
MyDataGrid.SelectedItem = r.Item;
// Scroll while dragging...
DependencyObject d = MyDataGrid;
while (!(d is ScrollViewer))
{
d = VisualTreeHelper.GetChild(d, 0);
}
ScrollViewer scroll = d as ScrollViewer;
Point position = MyDataGrid.PointToScreen(Mouse.GetPosition(r));
// create this textbox to test in real time the value of gridOrigin
textBox1.Text = position.ToString();
double topMargin = scroll.ActualHeight * .15;
double bottomMargin = scroll.ActualHeight * .80;
if (position.Y * -1 < topMargin)
scroll.LineUp(); // <-- needs a mechanism to control the speed of the scroll.
if (position.Y * -1 > bottomMargin)
scroll.LineDown(); // <-- needs a mechanism to control the speed of the scroll.
}

Using Shift key Multi selection of checkbox( Find Controls within 2 points/ rectangle

In order to select multiple checkbox within Wrap panel using Shift Key.
Capturing the Mouse down event position on Shift Keydown, on second mouse down with shift keydown, getting the 2 positions of the selection, then Need to Select the checkbox control with in the selected area.
How do I find the controls within 2 positions (System.Window.Point) or System.Windows.rect. The following code is selecting all of the checkbox within the wrappanel(lesscolorpanel).
private System.Windows.Point startPoint;
System.Windows.Point checkpPoint;
private System.Windows.Point PointWhereMouseIs;
private void LessColourPanel_OnPreviewMouseDown(object sender, MouseButtonEventArgs e)
{
if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
{
if (startPoint == checkpPoint)
{
//GET THE MOUSE POSITION
startPoint = Mouse.GetPosition(lessColourPanel);
PointWhereMouseIs = checkpPoint;
}
else if(PointWhereMouseIs==checkpPoint)
{
//CAPTURE END MOUSE POSITION
PointWhereMouseIs = Mouse.GetPosition(lessColourPanel);
//FIND CONTROLS WIHIN RECTANGLE
Rect selareaRect = new Rect(startPoint, PointWhereMouseIs);
foreach (System.Windows.Controls.CheckBox chkitemBox in FindVisualChildren<System.Windows.Controls.CheckBox>(lessColourPanel))
{
var rectBounds = VisualTreeHelper.GetDescendantBounds(chkitemBox);
Vector vector = VisualTreeHelper.GetOffset(chkitemBox);
rectBounds.Offset(vector);
if (rectBounds.IntersectsWith(selareaRect))
{
chkitemBox.IsChecked = true;
}
}
startPoint = checkpPoint;
}
}
}
Got it, and for viewers refer Ashley Davis post
The credit goes to Ashley Davis.

Problem getting the actual width of control before rendering in wpf

I have a wpf window that hosts a control.
The window's height and width are set to SizeToControl.
Now I need to position this Window relative to the position of its parent window.(basically the Top right position).
(So my windows Top = ParentWindow.Top, and Left = ParentWindow.Left + ParentWindow.ActualWidth - control.ActualWidth so that my window is positioned inside the parent window but to its right corner)
So i will need to set the Top and Left of the window. To do this I need the Actual Width of the control that is being hosted inside it....but I can only get this once I actually do,
Window.Show(control,parent)
Is there a way to get around this problem? How do I get the actual rendered width of the control before it is actually shown?
Thanks!
Have you tried this approach?
public partial class ShellWindow : Window
{
public ShellWindow(IShellPresentationModel model)
{
InitializeComponent();
this.Loaded += ShellWindow_Loaded;
}
void ShellWindow_Loaded(object sender, RoutedEventArgs e)
{
var innerWindow = new InnerWindow();
innerWindow.Owner = this;
innerWindow.Loaded += InnerWindow_Loaded;
innerWindow.Show();
}
void InnerWindow_Loaded(object sender, RoutedEventArgs e)
{
var w = (InnerWindow)sender;
w.Owner = this;
w.Top = this.Top;
w.Left = this.Left + this.ActualWidth - w.ActualWidth;
}
}

moving multiple controls

I need to move a multiple textboxes with a mouse cursor.
I decided that I do it that way.
If a textbox is clicked (and Control button is pressed) textbox is added to list of selected items. Then when button is still pressed and when mouse moves I do an operation of moving controls. However my code doesn't work well. Textboxes are moving but very very fast. Here is my code
List<TextBox> items;
private void txtBox_PreviewMouseDown(object sender, RoutedEventArgs e)
{
isClicked = true;
startPoint = Mouse.GetPosition( (sender as TextBox).Parent);
items = CurrentSelection;
}
private void txtBox_PreviewMouseMove(object sender, RoutedEventArgs e)
{
Point mousePos = Mouse.GetPosition(parentCanvas);
if (isClicked)
{
foreach (TextBox item in items)
{
double left = Canvas.GetLeft(item);
double top = Canvas.GetTop(item);
Canvas.SetLeft(item, left + (startPoint.X - mousePos.X));
Canvas.SetTop(item, top + (startPoint.Y - mousePos.Y));
}
}
}
Basically I iterate through all selected items and change their position on canvas. However I probably calculate a new position in a wrong way.
The problem is, that you always calculate the delta to the initial start point. You must actualize startPoint after every call to txtBox_PreviewMouseMove. Somethin like...
private void txtBox_PreviewMouseMove(object sender, RoutedEventArgs e) {
Point mousePos = Mouse.GetPosition(parentCanvas);
if (isClicked){
foreach (TextBox item in items) {
double left = Canvas.GetLeft(item);
double top = Canvas.GetTop(item);
Canvas.SetLeft(item, left + (startPoint.X - mousePos.X));
Canvas.SetTop(item, top + (startPoint.Y - mousePos.Y));
}
startPoint=mousePoint;
}
}
...should do the job. Another thing I have seen, is that the direction is probably inverted. This can be easily corrected. Change the calculcation to...
Canvas.SetLeft(item, left + (mousePos.X-startPoint.X ));
Canvas.SetTop(item, top + (mousePos.Y-startPoint.Y));
... and this problem should also be gone.

Scroll with mousewheel and zoom image with panning

I would like to make a small silverlight app which displays one fairly large image which can be zoomed in by scrolling the mouse and then panned with the mouse.
it's similar to the function in google maps and i do not want to use deepzoom.
here is what i have at the moment. please keep in mind that this is my first silverlight app:
this app is just for me to see it's a good way to build in a website. so it's a demo app and therefor has bad variable names.
the initial image is 1800px width.
private void sc_MouseWheel(object sender, MouseWheelEventArgs e)
{
var st = (ScaleTransform)plaatje.RenderTransform;
double zoom = e.Delta > 0 ? .1 : -.1;
st.ScaleX += zoom;
st.ScaleY += zoom;
}
this works, but could use some smoothing and it's positioned top left and not centered.
the panning is like this:
found it # Pan & Zoom Image
and converted it to this below to work in silverlight
Point start;
Point origin;
bool captured = false;
private void plaatje_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
plaatje.CaptureMouse();
captured = true;
var tt = (TranslateTransform)((TransformGroup)plaatje.RenderTransform)
.Children.First(tr => tr is TranslateTransform);
start = e.GetPosition(canvasje);
origin = new Point(tt.X, tt.Y);
}
private void plaatje_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
plaatje.ReleaseMouseCapture();
captured = false;
}
private void plaatje_MouseMove(object sender, MouseEventArgs e)
{
if (!captured) return;
var tt = (TranslateTransform)((TransformGroup)plaatje.RenderTransform).Children.First(tr => tr is TranslateTransform);
double xVerschuiving = start.X - e.GetPosition(canvasje).X;
double yVerschuiving = start.Y - e.GetPosition(canvasje).Y;
tt.X = origin.X - xVerschuiving;
tt.Y = origin.Y - yVerschuiving;
}
so the scaling isn't smooth and the panning isn't working, because when i click it, the image disappears.
first thing I noticed was this:
var st = (ScaleTransform)plaatje.RenderTransform;
and
(TransformGroup)plaatje.RenderTransform
. So in one handler, you're casting "plaatje.RenderTransform" to ScaleTransform, in the other you're casting to TransformGroup?
This is probably causing an exception, making your image disappear.
For the zooming part, you might want to try setting the RenderTransformOrigin of the object you want to scale ("plaatje"?) to "0.5,0.5", meaning the center of the UI element. So the image will be scaled around its center point instead of its top left corner.
Cheers, Alex

Resources