I have a rectangle shape in a stackpanel and i want to drag and drop in a grid with the mouse using WPF!
I appreciate it if someone can help me?
Thanks to everyone.
A very simple implementation follows. It simply handles the Mouse button down/up/move events of the Rectangle in order to position it along with mouse movement. There is no error checking and nothing to prevent the user from dragging the rectangle off of the Canvas and leaving it there.
XAML:
<Window x:Class="WpfApplication6.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>
<Canvas Name="canvas">
<Rectangle
Name="rect"
Width="50"
Height="50"
Canvas.Left="0"
Canvas.Top="0"
Fill="Red"
MouseLeftButtonDown="rect_MouseLeftButtonDown"
MouseLeftButtonUp="rect_MouseLeftButtonUp"
MouseMove="rect_MouseMove"
/>
</Canvas>
</Grid>
</Window>
Code Behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApplication6
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private bool _isRectDragInProg;
public MainWindow()
{
InitializeComponent();
}
private void rect_MouseLeftButtonDown( object sender, MouseButtonEventArgs e )
{
_isRectDragInProg = true;
rect.CaptureMouse();
}
private void rect_MouseLeftButtonUp( object sender, MouseButtonEventArgs e )
{
_isRectDragInProg = false;
rect.ReleaseMouseCapture();
}
private void rect_MouseMove( object sender, MouseEventArgs e )
{
if( !_isRectDragInProg ) return;
// get the position of the mouse relative to the Canvas
var mousePos = e.GetPosition(canvas);
// center the rect on the mouse
double left = mousePos.X - (rect.ActualWidth / 2);
double top = mousePos.Y - (rect.ActualHeight / 2);
Canvas.SetLeft( rect, left );
Canvas.SetTop( rect, top );
}
}
}
For implementing drag and drop in an items control where the items are laid out by anything other than a canvas, then I would highly recommend checking out Bea Stollnitz solution. This is a completely reusable solution to drag and drop between any items control using attached properties.
Update: given that Bea's blog is gone, there are other posts that are based on her solution still available:
https://www.codeproject.com/Articles/43614/Drag-and-Drop-in-WPF
http://blogarchive.claritycon.com/blog/2009/03/generic-wpf-drag-and-drop-adorner
https://siderite.dev/blog/mvvm-drag-and-drop.html
Extending what #Ed S answered.The problem with using a Canvas is you can basically drag the controls beyond the boundaries. If you want to make sure it won't cross the boundaries, I created a simple application where if you have two shapes you can either move both of them together or drag individually. Ofcourse I have a checkbox with name ChkDual mode to decide if shapes have to move together or not. You can edit that functionality as you need.
<Grid>
<!--Set some height and width as you like-->
<Canvas x:Name="CnvBarCodeImage" AllowDrop="True">
</Canvas>
<Grid>
private void CreateUIShapes(int numberOfWindows)
{
//If you want multiple shapes put it inside a loop
Thumb th = null;
th = new Thumb();
th.Width = 200;
th.Height = 100;
th.Foreground = new SolidColorBrush(Windows.UI.Colors.Transparent);
th.BorderBrush = Colors.Green;
th.BorderThickness = new Thickness(3);
th.DragDelta += (sender, e) => Th_DragDelta(sender, e);
Canvas.SetLeft(th, 100);
Canvas.SetTop(th, 80);
CnvBarCodeImage.Children.Add(th);
}
private event Action<Thumb, double, double> ChangeDimensions;
private void Th_DragDelta(object sender, DragDeltaEventArgs e, List<Dimensions> limitedWindowMovements)
{
var selectedDraggableThumb = sender as Thumb;
double left = (Canvas.GetLeft(selectedDraggableThumb) >= 0) ? Canvas.GetLeft(selectedDraggableThumb) : 0;
double top = (Canvas.GetTop(selectedDraggableThumb) >= 0) ? Canvas.GetTop(selectedDraggableThumb) : 0;
if (ChkDualMode.IsChecked == true)
{
var otherDraggableThumbs = CnvBarCodeImage.Children.OfType<Thumb>().Where(x => x != selectedDraggableThumb).ToList();
var maxTopSelected = 0
var maxLeftSelected = 0;
//There may be n number of windows.
foreach (var item in otherDraggableThumbs)
{
//TOP
//Canvas.GetTop(SelectedDraggableThumb) <= 0 || Canvas.GetTop(item) <= 0 original.
if (Canvas.GetTop(selectedDraggableThumb) <= maxTopSelected || Canvas.GetTop(item) <= maxTopSelected)
{
if (e.VerticalChange <= 0)
{
ChangeDimensions -= BarCodeServiceView_ChangeDimensions;
return;
}
}
//LEFT
//Canvas.GetLeft(SelectedDraggableThumb) <= 0 || Canvas.GetLeft(item) <= 0 original.
else if (Canvas.GetLeft(selectedDraggableThumb) <= maxLeftSelected || Canvas.GetLeft(item) <= maxLeftSelected)
{
if (e.HorizontalChange <= 0)
{
ChangeDimensions -= BarCodeServiceView_ChangeDimensions;
return;
}
}
//RIGHT
else if (Canvas.GetLeft(selectedDraggableThumb) >=
CnvBarCodeImage.ActualWidth - selectedDraggableThumb.ActualWidth ||
Canvas.GetLeft(item) >= CnvBarCodeImage.ActualWidth - item.ActualWidth)
//|| Canvas.GetLeft(SelectedDraggableThumb) >= maxRightSelected
//|| Canvas.GetLeft(item) >= maxRightSelected)
{
if (e.HorizontalChange > 0)
{
ChangeDimensions -= BarCodeServiceView_ChangeDimensions;
return;
}
}
//BOTTOM
else if (Canvas.GetTop(selectedDraggableThumb) + selectedDraggableThumb.ActualHeight >= CnvBarCodeImage.ActualHeight ||
Canvas.GetTop(item) + item.ActualHeight >= CnvBarCodeImage.ActualHeight)
{
if (e.VerticalChange >= 0)
{
ChangeDimensions -= BarCodeServiceView_ChangeDimensions;
return;
}
}
if (ChangeDimensions == null)
{
ChangeDimensions += BarCodeServiceView_ChangeDimensions;
}
}
foreach (var item in otherDraggableThumbs)
{
ChangeDimensions?.Invoke(item, e.HorizontalChange, e.VerticalChange);
}
left = (Canvas.GetLeft(selectedDraggableThumb) >= CnvBarCodeImage.ActualWidth) ? CnvBarCodeImage.ActualWidth : left;
top = (Canvas.GetTop(selectedDraggableThumb) >= CnvBarCodeImage.ActualHeight) ? CnvBarCodeImage.ActualHeight : top;
Canvas.SetLeft(selectedDraggableThumb, left + e.HorizontalChange);
Canvas.SetTop(selectedDraggableThumb, top + e.VerticalChange);
}
else
{
//In single mode limit the movement as well.
int.TryParse(selectedDraggableThumb.Name, out var indexFromName);
var limitedDimensionForWindow = limitedWindowMovements[indexFromName];
var maxTop = limitedDimensionForWindow.MaxTopPossible == null ? 0 : limitedDimensionForWindow.MaxTopPossible;
var maxLeft = limitedDimensionForWindow.MaxLeftPossible == null ? 0 : limitedDimensionForWindow.MaxLeftPossible;
var maxRight = limitedDimensionForWindow.MaxRightPossible == null ? CnvBarCodeImage.ActualWidth - selectedDraggableThumb.ActualWidth : limitedDimensionForWindow.MaxRightPossible;
var maxBottom = limitedDimensionForWindow.MaxBottomPossible == null ? CnvBarCodeImage.ActualHeight - selectedDraggableThumb.ActualHeight : limitedDimensionForWindow.MaxBottomPossible;
if (Canvas.GetTop(selectedDraggableThumb) <= maxTop)
{
if (e.VerticalChange <= 0)
{
return;
}
}
else if (Canvas.GetLeft(selectedDraggableThumb) <= maxLeft)
{
if (e.HorizontalChange <= 0)
{
return;
}
}
else if (Canvas.GetLeft(selectedDraggableThumb) >= maxRight)
{
if (e.HorizontalChange >= 0)
{
return;
}
}
else if (Canvas.GetTop(selectedDraggableThumb) >= maxBottom)
{
if (e.VerticalChange >= 0)
{
return;
}
}
left = (Canvas.GetLeft(selectedDraggableThumb) >= CnvBarCodeImage.ActualWidth) ? CnvBarCodeImage.ActualWidth : left;
top = (Canvas.GetTop(selectedDraggableThumb) >= CnvBarCodeImage.ActualHeight) ? CnvBarCodeImage.ActualHeight : top;
Canvas.SetLeft(selectedDraggableThumb, left + e.HorizontalChange);
Canvas.SetTop(selectedDraggableThumb, top + e.VerticalChange);
}
}
private void BarCodeServiceView_ChangeDimensions(Thumb sender, double arg1, double arg2)
{
if (sender != null)
{
double left = (Canvas.GetLeft(sender) > 0) ? Canvas.GetLeft(sender) : 0;
double top = (Canvas.GetTop(sender) > 0) ? Canvas.GetTop(sender) : 0;
Canvas.SetLeft(sender, left + arg1);
Canvas.SetTop(sender, top + arg2);
}
}
Related
I think it is a pretty common situation, but I can't find a solution that I need.
My case is, I have a DataGrid inside ScrollViewer. DataGrid has such params
MinHeight="350"
MaxHeight="350"
So, it is means that I have a dataGrid with constant height inside ScrollViewer. And DataGrid can contain (example) 300 items, so it has a scroll and ScrollViewer also has a scroll.
What I need is when user put a mouse on DataGrid and scroll down, so content inside DataGrid scrolling up to the last item and if came to last item it means that now we should get scroll event to ScrollViewer and continuous scroll whole page...
I found a few solutions on SO like this two
Mouse scroll not working in a scroll viewer with a wpf datagrid and additional UI elements
ScrollViewer mouse wheel not working
I checked an answers, but them doesn't fit to my problem. Because what I get is - when user put mouse on DataGrid and try scroll, so DataGrid did not get scroll event ever, just ScrollViewer get scroll event...
How to fix it?
XAML
<Window x:Class="so_wpf_test_1.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:so_wpf_test_1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Border Padding="10" Background="Yellow">
<ScrollViewer x:Name="sv">
<StackPanel Orientation="Vertical">
<DataGrid x:Name="dg" MinHeight="350" MaxHeight="350" ScrollViewer.ScrollChanged="dg_ScrollChanged">
</DataGrid>
<Button>A button that doesn't do anything</Button>
<DataGrid x:Name="dg2" MinHeight="350" MaxHeight="350" ScrollViewer.ScrollChanged="dg_ScrollChanged">
</DataGrid>
</StackPanel>
</ScrollViewer>
</Border>
</Window>
Code-behind
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace so_wpf_test_1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var items = new ObservableCollection<Item>();
for (int i = 1; i <= 50; ++i)
{
items.Add(new Item($"test {i}", $"abcd {i}", $"dcba {i}"));
}
dg.ItemsSource = items;
dg2.ItemsSource = items;
dg.PreviewMouseWheel += Dg_PreviewMouseWheel;
dg2.PreviewMouseWheel += Dg_PreviewMouseWheel;
}
private void Dg_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
var m_dg = sender as DataGrid;
var scroll = GetScrollViewer(m_dg);
// if scrolling to bottom and beyond...
if (e.Delta < 0 && scroll.VerticalOffset == scroll.ScrollableHeight)
{
sv.ScrollToVerticalOffset(sv.VerticalOffset - e.Delta);
}
// if scrolling to top and beyond...
else if (e.Delta > 0 && scroll.VerticalOffset == 0)
{
sv.ScrollToVerticalOffset(sv.VerticalOffset - e.Delta);
}
else
{
// nothing special: scroll the dg if it is the case (WPF does this automatically)
}
int idx = 0;
// if scrolling down
if (e.Delta < 0)
{
// see the sketch
idx = dictLastVisible[m_dg] + 1;
Debug.WriteLine($"FROM {(m_dg == dg ? 1 : 2)} DOWN {idx}");
}
// if scrolling up
else if (e.Delta > 0)
{
// see the sketch
idx = dictFirstVisible[m_dg] - 1;
Debug.WriteLine($"FROM {(m_dg == dg ? 1 : 2)} UP {idx}");
}
// if the index does not represent nothing
if (idx != 0)
{
// transform index to be 0-based
--idx;
// scroll that row into view
m_dg.ScrollIntoView(m_dg.Items[idx]);
}
}
/// <summary>
/// Source: https://stackoverflow.com/a/41136328/258462
/// </summary>
/// <param name="element"></param>
/// <returns></returns>
public static ScrollViewer GetScrollViewer(UIElement element)
{
if (element == null) return null;
ScrollViewer retour = null;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element) && retour == null; i++)
{
if (VisualTreeHelper.GetChild(element, i) is ScrollViewer)
{
retour = (ScrollViewer)(VisualTreeHelper.GetChild(element, i));
}
else
{
retour = GetScrollViewer(VisualTreeHelper.GetChild(element, i) as UIElement);
}
}
return retour;
}
Dictionary<DataGrid, int> dictLastVisible = new Dictionary<DataGrid, int>();
Dictionary<DataGrid, int> dictFirstVisible = new Dictionary<DataGrid, int>();
private void dg_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
var dg = (DataGrid)sender;
int idxb = -1, idxe = -1; // b = beginning, e = end; both invalid initially
// from the first row towards the last row
for (int i = 0; i < dg.Items.Count; i++)
{
var v = (DataGridRow)dg.ItemContainerGenerator.ContainerFromItem(dg.Items[i]);
if (v != null)
{
idxb = i + 1; // compute the beginning row in the viewport
break;
}
}
// from the beginning row towards the last row
for (int i = idxb + 1; i < dg.Items.Count; i++)
{
var v = (DataGridRow)dg.ItemContainerGenerator.ContainerFromItem(dg.Items[i]);
if (v == null)
{
idxe = i - 1 + 1; // compute the end row in the viewport
break;
}
}
// store the two indices in two dictionaries
dictFirstVisible[dg] = idxb;
dictLastVisible[dg] = idxe;
}
}
public class Item
{
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }
public Item(string a, string b, string c)
{
A = a;
B = b;
C = c;
}
}
}
Possibly helping sketch
If the code does not run or has bugs, or the comments are not clear enough, please post a comment. I hope you will be able to extend the code for a dynamic number of DataGrids if you have this requirement.
I have a ScrollViewer inside which I have some expanders and of the Expander's content has a Canvas. I am drawing two rectangles on the Canvas which are Thumb controls that can be dragged around. Problem is, whenever I press on the rectangles and try to drag, it somehow assumes that I want to scroll the entire page and the Drag never happens. How can I solve this problem inside the ScrollViewer.
There is a property called CanBeScrollAnchorwhich I saw on MSDN for UWP that says the property is used for (Gets or sets a value that indicates whether the UIElement can be a candidate for scroll anchoring.). But setting that to false doesn't help. (I am adding the WPF tag because the concept is the same). Please help
Edit: This issue occurs only on the touch screen.
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Hidden">
<StackPanel Orientation="Vertical" HorizontalAlignment="Stretch">
<uwpControls:Expander>
<!--Some Content-->
</uwpControls:Expander>
<uwpControls:Expander HeaderStyle="{StaticResource ToggleButtonFullWidthHeader}"
Background="{StaticResource ListViewItemBackgroundBrush}" Margin="0,20,0,0" HorizontalAlignment="Stretch" Header="DragDrop">
<Grid x:Name="gridBarImagePanel" Grid.Row="4" BorderBrush="Black" BorderThickness="2">
<uwpControls:ImageEx x:Name="BarCodeImage" IsCacheEnabled="True" Source="..\SampleImage\demo.png"
Stretch="UniformToFill" />
<Canvas x:Name="cnvBarCodeImage" Canvas.ZIndex="100" VerticalAlignment="Stretch">
</Canvas>
</Grid>
</uwpControls:Expander>
</StackPanel>
</ScrollViewer>
In the code behind, I am calling this method to draw two Thumb controls on the Canvas dynamically.
public sealed partial class SomeControl:Page
{
event Action<Thumb, double, double> ChangeDimensions;
public void OnSomeButtonClick(object sender,EventArgs e)
{
//TEST(Remove this)
dimensions.Add(new Dimensions()
{
Height = 80,
Width = 150,
left = 250,
Top = 40,
BorderColor = BrushCollection[0],
MaxLeftPossible = null,
MaxTopPossible = null,//280
MaxRightPossible = null,
MaxBottomPossible = null,
});
dimensions.Add(new Dimensions()
{
Height = 80,
Width = 150,
left = 250,
Top = 150,
BorderColor = BrushCollection[1],
MaxLeftPossible = null,
MaxTopPossible = null,//280
MaxRightPossible = null,
MaxBottomPossible = null,
});
//CreateUIShapes(SelectedRowItem.WindowLocations.Count, dimensions);
CreateUIShapes(2, dimensions);
}
private void CreateUIShapes(int numberOfWindows, List<Dimensions> dimensions)
{
Thumb th = null;
for (int i = 0; i < numberOfWindows; i++)
{
th = new Thumb();
th.Name = string.Format("{0}{1}", "Thumb", i + 1);
var item = dimensions[i];
th.Width = item.Width;
th.Height = item.Height;
th.Foreground = new SolidColorBrush(Windows.UI.Colors.Transparent);
th.BorderBrush = item.BorderColor;
th.BorderThickness = new Thickness(3);
th.DragDelta += (sender, e) => Th_DragDelta(sender, e, dimensions);
th.DragCompleted += (sender, e) => Th_DragCompleted(sender, e);
Canvas.SetLeft(th, CheckAndGetItemToLeft(item.left, i));
Canvas.SetTop(th, CheckAndGetItemTotop(item.Top, i));
cnvBarCodeImage.Children.Add(th);
}
}
//This is the code to drag and drop.
private void Th_DragDelta(object sender, DragDeltaEventArgs e, List<Dimensions> LimitedWindowMovements)
{
var SelectedDraggableThumb = sender as Thumb;
double left = (Canvas.GetLeft(SelectedDraggableThumb) >= 0) ? Canvas.GetLeft(SelectedDraggableThumb) : 0;
double top = (Canvas.GetTop(SelectedDraggableThumb) >= 0) ? Canvas.GetTop(SelectedDraggableThumb) : 0;
if (ChkDualMode.IsChecked == true)
{
var OtherDraggableThumbs = cnvBarCodeImage.Children.OfType<Thumb>().Where(x => x != SelectedDraggableThumb);
var maxTopSelected = LimitedWindowMovements[0].MaxTopPossible == null ? 1 : LimitedWindowMovements[0].MaxTopPossible;
var maxBottomSelected = LimitedWindowMovements[0].MaxBottomPossible == null ? BarCodeImage.ActualHeight - SelectedDraggableThumb.ActualHeight : LimitedWindowMovements[0].MaxBottomPossible;
var maxLeftSelected = LimitedWindowMovements[0].MaxLeftPossible == null ? 0 : LimitedWindowMovements[0].MaxLeftPossible;
var maxRightSelected = LimitedWindowMovements[0].MaxRightPossible == null ? BarCodeImage.ActualWidth - SelectedDraggableThumb.Width : LimitedWindowMovements[0].MaxRightPossible;
//Boundry case for top->Current element.
//Don't allow further up.
if (top < maxTopSelected) //Hardcoding for now. top < 1 original.
{
if (e.VerticalChange <= 1)
{
ChangeDimensions -= BarCodeServiceView_ChangeDimensions;
return;
}
}
//Boundry case for bottom->Current element.
//Don't allow further down.
//Canvas.GetTop(SelectedDraggableThumb) >= BarCodeImage.ActualHeight - SelectedDraggableThumb.ActualHeight original.
else if (Canvas.GetTop(SelectedDraggableThumb) >= maxBottomSelected)
{
if (e.VerticalChange > 0)
{
ChangeDimensions -= BarCodeServiceView_ChangeDimensions;
return;
}
}
//Boundry case for left->Current element.
//Don't allow further left.
//Canvas.GetLeft(SelectedDraggableThumb) <= 0 original.
else if (Canvas.GetLeft(SelectedDraggableThumb) <= maxLeftSelected)
{
if (e.HorizontalChange <= 1)
{
ChangeDimensions -= BarCodeServiceView_ChangeDimensions;
return;
}
}
//Boundry case for left->Current element.
//Don't allow further right.
//Math.Round(Canvas.GetLeft(SelectedDraggableThumb), 1) >= BarCodeImage.ActualWidth - SelectedDraggableThumb.Width original.
else if (Math.Round(Canvas.GetLeft(SelectedDraggableThumb), 1) >= maxRightSelected)
{
if (e.HorizontalChange >= 0)
{
ChangeDimensions -= BarCodeServiceView_ChangeDimensions;
return;
}
}
//There may be n number of windows.
foreach (var item in OtherDraggableThumbs)
{
//Boundry case for the other thumb moving up.
//Don't allow further up.
//var OtherTop = Canvas.GetTop(item); original
var OtherTop = Canvas.GetTop(item);
if (OtherTop < maxTopSelected)
{
if (e.VerticalChange <= 1)
{
ChangeDimensions -= BarCodeServiceView_ChangeDimensions;
return;
}
}
//Boundry case for the other thumb moving bottom
//Don't allow further bottom.
//BarCodeImage.ActualHeight - SelectedDraggableThumb.ActualHeight original
if (Canvas.GetTop(item) >= maxBottomSelected)
{
if (e.VerticalChange > 0)
{
ChangeDimensions -= BarCodeServiceView_ChangeDimensions;
return;
}
}
//Boundry case for the other thumb moving left.
//Don't allow further left
//Canvas.GetLeft(item) <= 0 original
if (Canvas.GetLeft(item) <= maxLeftSelected)
{
if (e.HorizontalChange <= 1)
{
ChangeDimensions -= BarCodeServiceView_ChangeDimensions;
return;
}
}
//Boundry case for the other thumb moving right.
//Don't allow further right
//Math.Round(Canvas.GetLeft(item), 1) >= BarCodeImage.ActualWidth - item.Width original
if (Math.Round(Canvas.GetLeft(item), 1) >= maxRightSelected)
{
if (e.HorizontalChange >= 0)
{
ChangeDimensions -= BarCodeServiceView_ChangeDimensions;
return;
}
}
if (ChangeDimensions == null)
{
ChangeDimensions += BarCodeServiceView_ChangeDimensions;
}
}
foreach (var item in OtherDraggableThumbs)
{
ChangeDimensions?.Invoke(item, e.HorizontalChange, e.VerticalChange);
}
}
left = (Canvas.GetLeft(SelectedDraggableThumb) > BarCodeImage.ActualWidth - SelectedDraggableThumb.ActualWidth) ? BarCodeImage.ActualWidth - SelectedDraggableThumb.ActualWidth : left;
top = (Canvas.GetTop(SelectedDraggableThumb) > BarCodeImage.ActualHeight - SelectedDraggableThumb.ActualHeight) ? BarCodeImage.ActualHeight - SelectedDraggableThumb.ActualHeight : top;
Canvas.SetLeft(SelectedDraggableThumb, left + e.HorizontalChange);
Canvas.SetTop(SelectedDraggableThumb, top + e.VerticalChange);
}
//When one thumb moves, I want to move the other in the same direction.
private void BarCodeServiceView_ChangeDimensions(Thumb sender, double arg1, double arg2)
{
if (sender != null)
{
//4025e8df
double left = (Canvas.GetLeft(sender) > 0) ? Canvas.GetLeft(sender) : 0;
double top = (Canvas.GetTop(sender) > 0) ? Canvas.GetTop(sender) : 0;
left = (Canvas.GetLeft(sender) > BarCodeImage.ActualWidth - sender.ActualWidth) ? BarCodeImage.ActualWidth - sender.ActualWidth : left;
top = (Canvas.GetTop(sender) > BarCodeImage.ActualHeight - sender.ActualHeight) ? BarCodeImage.ActualHeight - sender.ActualHeight : top;
Canvas.SetLeft(sender, left + arg1);
Canvas.SetTop(sender, top + arg2);
}
}
private void Th_DragCompleted(object sender, DragCompletedEventArgs e)
{
//Do something.
foreach (var item in cnvBarCodeImage.Children.OfType<Thumb>())
{
ChangeDimensions -= BarCodeServiceView_ChangeDimensions;
}
}
}
public class Dimensions
{
public double Height { get; set; }
public double Width { get; set; }
public double left { get; set; }
public double Top { get; set; }
public Windows.UI.Xaml.Media.Brush BorderColor { get; set; }
/// <summary>
/// If no restriction needed specify null
/// </summary>
public double? MaxTopPossible { get; set; }
/// <summary>
/// If no restriction needed specify null
/// </summary>
public double? MaxLeftPossible { get; set; }
/// <summary>
/// If no restriction needed specify null
/// </summary>
public double? MaxRightPossible { get; set; }
/// <summary>
/// If no restriction needed specify null
/// </summary>
public double? MaxBottomPossible { get; set; }
}
I'm having trouble setting the VerticalScroll/HorizontalScroll.Value property. Every time I set the value, the scrollbar moves, then snaps back (see screenshot below)
Here is the code for my user control:
using System.Drawing;
using System.Windows.Forms;
namespace MyGanttChart
{
public class Chart : UserControl
{
public Chart()
{
HorizontalScroll.Visible = true;
VerticalScroll.Visible = true;
}
protected override void OnMouseWheel(MouseEventArgs e)
{
base.OnMouseWheel(e);
ScrollEventType scrollType = ScrollEventType.SmallIncrement;
if (e.Delta > 0)
scrollType = ScrollEventType.SmallDecrement;
ScrollOrientation orientation = ScrollOrientation.VerticalScroll;
if (ModifierKeys == Keys.Shift)
orientation = ScrollOrientation.HorizontalScroll;
ScrollEventArgs args = new ScrollEventArgs(scrollType, 1, orientation);
OnScroll(args);
}
protected override void OnScroll(ScrollEventArgs se)
{
base.OnScroll(se);
if (se.ScrollOrientation == ScrollOrientation.HorizontalScroll)
{
//if (se.Type == ScrollEventType.SmallIncrement || se.Type == ScrollEventType.LargeIncrement)
// X -= HorizontalScroll.LargeChange; // se.NewValue;
//else if (se.Type == ScrollEventType.SmallDecrement || se.Type == ScrollEventType.LargeDecrement)
// X += HorizontalScroll.LargeChange;
if ((se.Type == ScrollEventType.SmallIncrement || se.Type == ScrollEventType.LargeIncrement) &&
HorizontalScroll.Value + HorizontalScroll.LargeChange <= HorizontalScroll.Maximum)
{
HorizontalScroll.Value += HorizontalScroll.LargeChange;
}
else if ((se.Type == ScrollEventType.SmallDecrement || se.Type == ScrollEventType.LargeDecrement) &&
HorizontalScroll.Value - HorizontalScroll.LargeChange >= HorizontalScroll.Minimum)
{
HorizontalScroll.Value -= HorizontalScroll.LargeChange;
}
}
else if (se.ScrollOrientation == ScrollOrientation.VerticalScroll)
{
//if (se.Type == ScrollEventType.SmallIncrement || se.Type == ScrollEventType.LargeIncrement)
// Y -= VerticalScroll.LargeChange;
//else if (se.Type == ScrollEventType.SmallDecrement || se.Type == ScrollEventType.LargeDecrement)
// Y += VerticalScroll.LargeChange;
if ((se.Type == ScrollEventType.SmallIncrement || se.Type == ScrollEventType.LargeIncrement) &&
VerticalScroll.Value + VerticalScroll.LargeChange <= VerticalScroll.Maximum)
{
VerticalScroll.Value += VerticalScroll.LargeChange;
}
else if ((se.Type == ScrollEventType.SmallDecrement || se.Type == ScrollEventType.LargeDecrement) &&
VerticalScroll.Value - VerticalScroll.LargeChange >= VerticalScroll.Minimum)
{
VerticalScroll.Value -= VerticalScroll.LargeChange;
}
}
this.Invalidate(); //Force the control to redraw
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (!this.DesignMode)
Draw(e.Graphics, e.ClipRectangle);
}
public float X = 0;
public float Y = 0;
private void Draw(Graphics graphics, Rectangle rect)
{
graphics.TranslateTransform(X, Y);
graphics.Clear(Color.White);
Point center = new Point(rect.X + rect.Width / 2, rect.Y + rect.Height / 2);
graphics.DrawString("hi", this.Font, new SolidBrush(Color.Black), center.X, center.Y, new StringFormat() { Alignment = StringAlignment.Center});
graphics.Flush();
}
}
}
(The control view currently does not move - I had that working with the X and Y values, but I'm working on the scrollbar values right now)
I've seen this question but setting the value twice or calling PerformLayout() does not seem to work for me. Any suggestions?
From what I see of your code, you don't need any custom code to manage the scrolling of your drawing.
First, you need to add a child panel inside your usercontrol which will be the container of the drawing. So you move the drawing code to this panel. You must ensure that this panel will resize itself if the drawing needs to be bigger. This is what will show the scrollbars on the usercontrol.
Second, you must set the AutoScroll property of your usercontrol to True. Doing so will ensure that any child control having a size or a position exceeding the usercontrol size can be scrolled. Have a look at the AutoScrollMargin property too. This is done automagically by the framework, so no other code is needed. Isn't it beautiful?
Finally, you can remove the two scrollbars you added.
Edit:
Moreover, when you draw, you don't need to compensate for the scrolling position. You just draw with origin 0,0 without taking care of the scroll. In addition, doing it this way will prevent any flickering caused by constantly redrawing.
I am creating a label control that allows resizing from the top and bottom of the label. It also only slides vertically when moved. I created the boundaries for its movement and for the bottom part of the resizable label, but I'm having trouble figuring out what I'm doing wrong for the top part. Whenever the mouse is dragged outside of the bounds from the top, it triggers the preset length of 450 pixels. I am using .SetBounds along with Math.Min.
using System;
using System.Drawing;
using System.Windows.Forms;
namespace EventTest
{
public partial class Form1 : Form
{
Point label1_MousePoint_01 = new Point();
Point label1_Start_01 = new Point();
Point label1_End_01 = new Point();
int label1_MouseSwitch_01;
public Form1()
{
InitializeComponent();
label1.MouseDown += Label1_MouseDown;
label1.MouseUp += Label1_MouseUp;
label1.MouseMove += Label1_MouseMove;
}
// Mouse Move Event
private void Label1_MouseMove(object sender, MouseEventArgs e)
{
if ((e.X < label1.Width && e.X > 0 && e.Y > 0 && e.Y < 4) || (e.X < label1.Width && e.X > 0 && e.Y > label1.Height - 4 && e.Y < label1.Height))
{
Cursor.Current = Cursors.SizeNS;
}
// Mouse Event Top Move
if (label1_MouseSwitch_01 == 1)
{
label1.SetBounds(0, Math.Max(e.Y + label1.Location.Y - label1_MousePoint_01.Y, 40), 120, Math.Min(label1.Height - e.Y + label1_MousePoint_01.Y, 450));
}
// Mouse Event Bottom Move
else if (label1_MouseSwitch_01 == 2)
{
label1.Height = Math.Min(660 - label1.Location.Y, e.Location.Y);
}
// Mouse Event Grab and Move
else if (label1_MouseSwitch_01 == 3)
{
int ny = Math.Min(Math.Max((label1.Location.Y - label1_MousePoint_01.Y + e.Y), 40), 660 - label1.Height);
label1.Location = new Point(0, ny);
}
}
// Mouse Up Event
private void Label1_MouseUp(object sender, MouseEventArgs e)
{
label1_MouseSwitch_01 = 0;
if (label1.Height < 20)
{
label1.Height = 20;
}
}
// Mouse Down Event
private void Label1_MouseDown(object sender, MouseEventArgs e)
{
label1_Start_01.Y = label1.Height;
label1_End_01.Y = label1.Top;
// Set Mouse Switch
if (e.Button == MouseButtons.Left)
{
label1_MousePoint_01 = e.Location;
if (e.Y > 0 && e.Y < 4)
{
Cursor.Current = Cursors.SizeNS;
label1_MouseSwitch_01 = 1;
}
else if (e.Y > label1.Height - 4 && e.Y < label1.Height)
{
Cursor.Current = Cursors.SizeNS;
label1_MouseSwitch_01 = 2;
}
else if (e.Y > 4 && e.Y < label1.Height - 4)
{
label1_MouseSwitch_01 = 3;
}
}
}
// Snap To Every 20 Pixels
public int RoundEr(int i)
{
return ((int)Math.Round(i / 20.0)) * 20;
}
}
}
Im using the toolkit GestureService.GestureListener, the implementation is going very well.
The main page contains a LongListSelector, and on the top (not visible to the user) I have my sliding menu that I slide using the GestureService.
when I try to scroll in the LongListSelector the menu on the top comes down, which is not good.
if im scrolling on the list don't slide the menu, other than that, slide the menu !
how to handle such an event.
thanks
Edit
<Grid x:Name="LayoutRoot">
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener DragDelta="GestureListener_DragDelta"
DragCompleted="GestureListener_DragCompleted" />
</toolkit:GestureService.GestureListener>
<phone:Panorama Foreground="Black">
<phone:PanoramaItem>
<Phone:LongListSelector x:Name="MyList"
ItemTemplate="{StaticResource MyListTemplate}"/>
</phone:PanoramaItem>
<phone:PanoramaItem>
</phone:PanoramaItem>
</phone:Panorama >
</Grid>
And this is my C# Code
private void CloseSettings()
{
var trans = _feContainer.GetVerticalOffset().Transform;
trans.Animate(trans.Y, 0, TranslateTransform.YProperty, 500, 0, new CubicEase //trans.Y, 0, TranslateTransform.YProperty, 120, 0, new CubicEase
{
EasingMode = EasingMode.EaseOut
});
_isSettingsOpen = false;
}
private void OpenSettings()
{
var trans = _feContainer.GetVerticalOffset().Transform;
trans.Animate(trans.Y, 400, TranslateTransform.YProperty, 200, 0, new CubicEase
{
EasingMode = EasingMode.EaseInOut
});
_isSettingsOpen = true;
}
private void ResetLayoutRoot()
{
if (!_isSettingsOpen)
_feContainer.SetVerticalOffset(0.0);
else
_feContainer.SetVerticalOffset(120.0);
}
private void GestureListener_DragDelta(object sender, DragDeltaGestureEventArgs e)
{
if (e.Direction == System.Windows.Controls.Orientation.Vertical && e.VerticalChange > 0 && !_isSettingsOpen)
{
double offset = _feContainer.GetVerticalOffset().Value + e.VerticalChange;
if (offset > _dragDistanceToOpen)
this.OpenSettings();
else
_feContainer.SetVerticalOffset(offset);
}
if (e.Direction == System.Windows.Controls.Orientation.Vertical && e.VerticalChange < 0 && _isSettingsOpen)
{
double offsetContainer = _feContainer.GetVerticalOffset().Value + e.VerticalChange;
if (offsetContainer < _dragDistanceToClose)
this.CloseSettings();
else
_feContainer.SetVerticalOffset(offsetContainer);
}
}
private void GestureListener_DragCompleted(object sender, DragCompletedGestureEventArgs e)
{
if (e.Direction == System.Windows.Controls.Orientation.Vertical && e.VerticalChange > 0 && !_isSettingsOpen)
{
if (e.VerticalChange < _dragDistanceToOpen)
this.ResetLayoutRoot();
else
this.OpenSettings();
}
if (e.Direction == System.Windows.Controls.Orientation.Vertical && e.HorizontalChange < 0 && _isSettingsOpen)
{
if (e.VerticalChange > _dragDistanceNegative)
this.ResetLayoutRoot();
else
this.CloseSettings();
}
}
Variables declared in the class, its working really good, but as i said before, when I scroll in my longListSelector, the menu slides down, i dont want that !
This only happens when the parent is not receiving the invokation call . What I suggest you to do is to add IsHitTestVisible =False to your Menu and see whether it works or not