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
Related
I have a drag and drop PopupBox in MaterialDesign. When drag and drop is done, the gui freezes and the data that is constantly renewed is not refreshed. How can I solve this Problem? Is it wrong to run in a separate thread? Is there just an overlooked point? Or is it all wrong?
my MouseUp Code
private void PortableButton_MouseUp(object sender, MouseButtonEventArgs e)
{
ThreadPool.QueueUserWorkItem(state => {
PortableButton.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(() =>
{
e.MouseDevice.Capture(null);
}));
});
}
MouseMove Code
private void PortableButton_MouseMove(object sender, MouseEventArgs e)
{
ThreadPool.QueueUserWorkItem(state => {
var ActuelHeight = MainBorder.ActualHeight;
var ActuelWidth = MainBorder.ActualWidth;
PortableButton.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(() =>
{
int _tempX = Convert.ToInt32(e.GetPosition(this).X);
int _tempY = Convert.ToInt32(e.GetPosition(this).Y);
if (_tempX < ActuelWidth && _tempX > 0 && _tempY < ActuelHeight && _tempY > 0)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
e.MouseDevice.Capture(PortableButton);
System.Windows.Thickness _margin = new System.Windows.Thickness();
_margin = MainGrid.Margin;
if (m_MouseX < _tempX)
{
_margin.Left += (_tempX - m_MouseX);
_margin.Right -= (_tempX - m_MouseX);
}
else
{
_margin.Left -= (m_MouseX - _tempX);
_margin.Right -= (_tempX - m_MouseX);
}
if (m_MouseY < _tempY)
{
_margin.Top += (_tempY - m_MouseY);
_margin.Bottom -= (_tempY - m_MouseY);
}
else
{
_margin.Top -= (m_MouseY - _tempY);
_margin.Bottom -= (_tempY - m_MouseY);
}
MainGrid.Margin = _margin;
m_MouseX = _tempX;
m_MouseY = _tempY;
}
}
}));
});
}
MouseLefButtonUp Code
double m_MouseX;
double m_MouseY;
private void PortableButton_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
ThreadPool.QueueUserWorkItem(state => {
this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(() =>
{
m_MouseX = e.GetPosition(this).X;
m_MouseY = e.GetPosition(this).Y;
}));
});
}
Xaml Code
<Grid Name="MainGrid" Margin="96,308,156,0" VerticalAlignment="Top" Height="65" >
<materialDesign:PopupBox MouseUp="PortableButton_MouseUp" MouseLeftButtonUp="PortableButton_MouseLeftButtonUp" MouseMove="PortableButton_MouseMove" Name="PortableButton" Style="{StaticResource MaterialDesignMultiFloatingActionPopupBox}"
PlacementMode="BottomAndAlignCentres" ToolTipService.Placement="Right"
materialDesign:ShadowAssist.ShadowDepth="Depth3"
ToolTip="MenĂ¼">
<StackPanel>
<Button Name="SystemButton" ToolTip="System" PreviewMouseLeftButtonDown="SystemButton_PreviewMouseLeftButtonDown">
<Image Source="/Images/Icons/systemIcon.png" Width="45" ></Image>
</Button>
<Button Name="TestButton" ToolTip="Test" PreviewMouseLeftButtonDown ="TestButton_PreviewMouseLeftButtonDown">
<Image Source="/Images/Icons/testIcon.png" Width="30"></Image>
</Button>
<Button Name="PosButton" ToolTip="Pos" PreviewMouseLeftButtonDown ="PosClick">
<Image Source="/Images/Icons/positionIcon.png" Width="30"></Image>
</Button>
</StackPanel>
</materialDesign:PopupBox>
</Grid>
I add xaml code. There is constantly refreshing data on the screen. I get these with a special protocol with serialPort. Since it will be a very long code, it can be tried with the for loop that counts in the timer.
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; }
}
public class CustomPickerRenderer : PickerRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Picker> e)
{
base.OnElementChanged(e);
if (this.Control != null)
{
var downarrow = UIImage.FromBundle("your image");
var textField = this.Control;
textField.RightViewMode = UITextFieldViewMode.Always;
textField.RightView = new UIImageView(downarrow);
}
}
}
I have using PickerRenderer for IOS and I want to make some space from right side.How to make padding from right side ? Here Image, please check
Xamarin Picker Arrow Workaround
In addition to #Pratik post, Clicking on the arrow won't work unless you make tapped event for the image.
XAML
<Grid>
<Picker
x:Name="catPicker"
Title="Select Type"/>
<Image
Margin="5"
HorizontalOptions="End"
Source="down_arrow">
<Image.GestureRecognizers>
<TapGestureRecognizer Tapped="Arrow_OnTapped" />
</Image.GestureRecognizers>
</Image>
</Grid>
C#
private void Arrow_OnTapped(object sender, EventArgs e)
{
catPicker.Focus();
}
Try using Grid with image and picker.
<Grid>
<Picker/>
<Image Source="arrow.png" HorizontalOptions="End" Magin="5"/>
</Grid>
may be it's help you
This is a custom renderer that allows you to add padding on the right side of an image for a picker...
It is applicable for an Entry Element
public class DefaultPickerRender : PickerRenderer
{
CALayer bottomLine;
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
{
base.OnElementChanged(e);
var element = (DefaultPicker)this.Element;
if (this.Control != null && this.Element != null && (element.Image != null))
{
var viewPadding = new UIView(frame: new CGRect(x: -10, y: 0, width: 12, height: 12));
var imageView = new UIImageView(frame: new CGRect(-10, 0, width: 12, height: 12));
imageView.Center = viewPadding.Center;
imageView.Image = UIImage.FromBundle(element.Image);
viewPadding.AddSubview(imageView);
Control.RightView = viewPadding;
Control.RightViewMode = UITextFieldViewMode.Always;
// Control.RightView = downarrow; //new UIImageView(downarrow);
Control.LeftView = new UIView(new CGRect(0, 0, 10, 0));
Control.LeftViewMode = UITextFieldViewMode.Always;
if (element.IsTransparent)
Control.BackgroundColor = UIColor.Clear;
else
Control.BackgroundColor = (new UIColor(red: 0.10f, green: 0.10f, blue: 0.10f, alpha: 1.00f)).ColorWithAlpha((nfloat)0.03); //#191919
bottomLine = new CALayer();
bottomLine.BackgroundColor = UIColor.Black.CGColor;
Control.BorderStyle = UITextBorderStyle.None;
Control.Layer.AddSublayer(bottomLine);
}
}
public override void Draw(CGRect rect)
{
base.Draw(rect);
bottomLine.Frame = new CGRect(0, Control.Frame.Height - 1, Control.Frame.Width, 2);
}
}
I have created the following Listbox.Itemtemplate:
<ListBox.ItemTemplate>
<DataTemplate>
<Image Name="ChannelImage" Source="{Binding ImageUrl}" Width="56" Height="56" Margin="0,0,28,0" Tap="ChannelImage_Tap" Opacity="0.5"/>
</DataTemplate>
</ListBox.ItemTemplate>
By default the image inside the ItemTemplate should have opacity 0.5, now I want to "Highlight" (set opacity to 1.0) the image when the user taps the image.
I made this with the following code (Tap="ChannelImage_Tap"):
private void ChannelImage_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
((Image)sender).Opacity = 1.0;
}
But I don't know how to set the image back to opacity 0.5 when the user taps another image.
Do the following code in ListBox selection_change event instead image_tap
//I assume your listbox selection changed is ListBoxImage_Selectionchange
//ListBoxImage is your ListBox name
// LastSelectedIndex define globally
int LastSelectedIndex =0;
private void ListBoxImage_Selectionchange(object sender, SelectionChangedEventArgs e)
{
if (ListBoxImage.SelectedIndex == -1)
return;
if(LastSelectedIndex>0)
{
ListBoxItem lastItem =this.ListImage.ItemContainerGenerator.ContainerFromIndex(LastSelectedIndex) as ListBoxItem;
Image lastImage = FindFirstElementInVisualTree<Image>(lastItem);
lastImage.Opacity = 0.5;
}
ListBoxItem selectedItem = this.ListImage.ItemContainerGenerator.ContainerFromIndex(ListImage.SelectedIndex) as ListBoxItem;
Image selectedImage = FindFirstElementInVisualTree<Image>(selectedItem);
selectedImage.Opacity = 1.0;
LastSelectedIndex = ListBoxImage.SelectedIndex;
ListImage.SelectedIndex = -1;
}
private T FindFirstElementInVisualTree<T>(DependencyObject parentElement) where T : DependencyObject
{
var count = VisualTreeHelper.GetChildrenCount(parentElement);
if (count == 0)
return null;
for (int i = 0; i < count; i++)
{
var child = VisualTreeHelper.GetChild(parentElement, i);
if (child != null && child is T)
{
return (T)child;
}
else
{
var result = FindFirstElementInVisualTree<T>(child);
if (result != null)
return result;
}
}
return null;
}
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);
}
}