Scroll over datagrid with click drag - wpf

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.
}

Related

Lost focus when viewModel is updated

I would like to update row of datagrid when selection is changed.
private void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Strint rowID = ((String)((DataGrid)sender).SelectedValue);
RadekTabulky row = Client.getRadek(rowID);
if(row != null)
{
dataGrid.SelectionChanged -= DataGrid_SelectionChanged;
int index = dataGrid.SelectedIndex;
viewModel.Sumy = new SumStorage(viewModel.Soubor, viewModel.Radky);
dataGrid.SelectedIndex = index;
dataGrid.SelectionChanged += DataGrid_SelectionChanged;
}
}
I wrote this simple code. But when I click on row, the row is selected, updated but it looks like grid lost focus and I cannot see which row is selected. When I click again at same row, it will get that blue color indicating it is selected.
Is there a way how to update viewModel without losing this focus?

Prevent WPF Image in border from panning too far

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.

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.

WPF Datagrid drag and drop questions

I have a WPF Datagrid and I'm implementing drag and drop functionality.
The datagrid has a list of "files" and the user can drag them and copy the file to the desktop.
This is done like this:
string[] files = new String[myDataGrid.SelectedItems.Count];
int ix = 0;
foreach (object nextSel in myDataGrid.SelectedItems)
{
files[ix] = ((Song)nextSel).FileLocation;
++ix;
}
string dataFormat = DataFormats.FileDrop;
DataObject dataObject = new DataObject(dataFormat, files);
DragDrop.DoDragDrop(this.myDataGrid, dataObject, DragDropEffects.Copy);
I have two questions:
1. When I want to drag multiple items- this is a problem because after I select a couple and start clicking on one to start dragging- only that gets selected and the other items get deselected. I tried the solution that is given here but for some reason it doesn't work.
2. I want to remove the dragged item from the datagrid after it is copied. The problem is that I don't know how to check if the file was copied or whether the user just dragged it on the screen without copying it.
I hope you can help me solve these problems.
Thanks!
I think this i what you are looking for:
add this code to the DataGrid__PreviewMouseLeftButtonDown event handler:
private void DataGrid_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
this.startingPosition = e.GetPosition(null);
DependencyObject dep = (DependencyObject)e.OriginalSource;
// iteratively traverse the visual tree until get a row or null
while ((dep != null) && !(dep is DataGridRow))
{
dep = VisualTreeHelper.GetParent(dep);
}
//if this is a row (item)
if (dep is DataGridRow)
{
//if the pointed item is already selected do not reselect it, so the previous multi-selection will remain
if (songListDB.SelectedItems.Contains((dep as DataGridRow).Item))
{
// now the drag will drag all selected files
e.Handled = true;
}
}
}
and now the draging won't change you selection.
Have a good luck!
I used that article to write my answer
Improved on finding the row.
Also selecting the clicked row when not dragging is added.
This now behaves exactly as other Microsoft selectors (eg Outlook)
public TreeDataGrid()
{
Loaded += TreeDataGrid_Loaded;
LoadingRow += new EventHandler<DataGridRowEventArgs>(TreeDataGrid_LoadingRow);
}
#region MultiSelect Drag
object toSelectItemOnMouseLeftButtonUp;
void TreeDataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
{
e.Row.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(Row_PreviewMouseLeftButtonDown);
e.Row.PreviewMouseLeftButtonUp += new MouseButtonEventHandler(Row_PreviewMouseLeftButtonUp);
}
void Row_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
DataGridRow row = (DataGridRow)sender;
toSelectItemOnMouseLeftButtonUp = null; // always clear selecteditem
if (SelectedItems.Contains(row.Item)) //if the pointed item is already selected do not reselect it, so the previous multi-selection will remain
{
e.Handled = true; // this prevents the multiselection from disappearing, BUT datagridcell still gets the event and sets DataGrid's private member _selectionAnchor
toSelectItemOnMouseLeftButtonUp = row.Item; // store our item to select on MouseLeftButtonUp
}
}
void Row_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
DataGridRow row = (DataGridRow)sender;
if (row.Item == toSelectItemOnMouseLeftButtonUp) // check if it's set and concerning the same row
{
if (SelectedItem == toSelectItemOnMouseLeftButtonUp) SelectedItem = null; // if the item is already selected whe need to trigger a change
SelectedItem = toSelectItemOnMouseLeftButtonUp; // this will clear the multi selection, and only select the item we pressed down on
typeof(DataGrid).GetField("_selectionAnchor", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(this, new DataGridCellInfo(row.Item, ColumnFromDisplayIndex(0))); // we need to set this anchor for when we select by pressing shift key
toSelectItemOnMouseLeftButtonUp = null; // handled
}
}
#endregion

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.

Resources