Resizing and Repositioning controls using canvas Drag drop.
In our previous article learned how to position list of control using Canvas and ItemsControl,In this article we willlearn how to resize and repositions the control using canvas and save their positions i.e. Height/Width of the control and top/left positions of control as per a canvas.
As Controls get the positions from their immediate parent canvas. So we will not be using Itemcontrol to display the controls so that canvas can have full control on the children(the controls that needs to get resized and reposition)
Below are the steps we need to follow for this:
Step 1: Lets use the same MainWindow and add a canvas control to it.The xaml for MainWindow.xaml should look like as below:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Canvas x:Name="DesigningCanvas" >
</Canvas>
</Grid>
Step 2:Lets Create a list containing the positions of controls and let bind that to the canvas children.
Step 3: Lets Create a class under ViewModel folder only named as “ControlDetails”, Class should look like:
namespace WpfApplication1.ViewModel
{
public class ControlDetails
{
public double Height
{
get;
set;
}
public double Width
{
get;
set;
}
public double Top
{
get;
set;
}
public double Left
{
get;
set;
}
}
}
Step 4: Lets go to the MainWindowViewModel and add the records into the ControlDetailsList to bind the ItemControl and to define the position of controls.
public void AddControlPositionToList()
{
controlDetailsList = new List<ControlDetails>();
ControlDetails controlDetails = new ControlDetails();
controlDetails.Height = 100;
controlDetails.Width = 200;
controlDetails.Left = 164;
controlDetails.Top = 86;
controlDetailsList.Add(controlDetails);
controlDetails = new ControlDetails();
controlDetails.Height = 200;
controlDetails.Width = 300;
controlDetails.Left = 349;
controlDetails.Top = 100;
controlDetailsList.Add(controlDetails);
controlDetails = new ControlDetails();
controlDetails.Height = 300;
controlDetails.Width = 400;
controlDetails.Left = 558;
controlDetails.Top = 40;
controlDetailsList.Add(controlDetails);
controlDetails = new ControlDetails();
controlDetails.Height = 400;
controlDetails.Width = 500;
controlDetails.Left = 733;
controlDetails.Top = 40;
controlDetailsList.Add(controlDetails);
}
So in above records we have defined the Height and width of the controls and Top and left margins or positions of the controls.
Step 5: Lets call this list in the IntitializeCollections or constructor where ever you want to bind the Itemcontrol.
public MainWindowViewModel()
{
AddControlPositionToList();
}
Step 6: Now lets bind the canvas children, that we need to do in MainWindow.cs.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
MainWindowViewModel mainWindowViewModel = new MainWindowViewModel();
this.DataContext = mainWindowViewModel;
BindCanvas(mainWindowViewModel);
}
public void BindCanvas(MainWindowViewModel mainWindowViewModel)
{
foreach (var details in mainWindowViewModel.controlDetailsList)
{
TextBox textBox = new TextBox();
if (details.Top >= 0)
textBox.SetValue(Canvas.TopProperty, Convert.ToDouble(details.Top));
if (details.Left >= 0)
textBox.SetValue(Canvas.LeftProperty, Convert.ToDouble(details.Left));
if (details.Height >= 0)
textBox.Height = details.Height;
if (details.Width >= 0)
textBox.Width = details.Width;
DesigningCanvas.Children.Add(textBox);
}
}
}
Now the above method binds the textbox as the canvas children and also assigns the positions already defined for the control in list.
Step 7:
Now to change the positions by drag drop the controls, we need to set the drag and drop points on t he canvas children, so now to access the canvas and its children from the MainWindowViewModel, we need to send the canvas control as the command parameter, so for that we are going to use Loaded event command.
As soon as our page and canvas would completes loaing that event should get fired.
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding LoadCommand}"
CommandParameter="{Binding ElementName=DesigningCanvas}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
Lets create the RelayCommand for Load Event in MainWindowViewModel.cs
private RelayCommand<Canvas> loadCommand;
public RelayCommand<Canvas> LoadCommand
{
get
{
return loadCommand ?? (loadCommand = new RelayCommand<Canvas>(x => AssignDragDrop(x)));
}
}
Step 8:
Lets now Create a Method to Assign Drag Drop positions to the Canvas Children but before doing that lets add a class for Adorner resizing , defining all the methods needs to resize the controls.So the ResizingAdorner should look like as below:
public class ResizingAdorner : Adorner
{
private readonly Thumb topLeft, topRight, bottomLeft, bottomRight, left, top, right, bottom;
private readonly VisualCollection visualChildren;
public ResizingAdorner(UIElement adornedElement)
: base(adornedElement)
{
visualChildren = new VisualCollection(this);
BuildAdornerCorner(ref topLeft, Cursors.SizeNWSE);
BuildAdornerCorner(ref topRight, Cursors.SizeNESW);
BuildAdornerCorner(ref bottomLeft, Cursors.SizeNESW);
BuildAdornerCorner(ref bottomRight, Cursors.SizeNWSE);
BuildAdornerCorner(ref left, Cursors.SizeWE);
BuildAdornerCorner(ref top, Cursors.SizeNS);
BuildAdornerCorner(ref right, Cursors.SizeWE);
BuildAdornerCorner(ref bottom, Cursors.SizeNS);
//CheckBox and CheckBoxGroup shouldn't resize
if (adornedElement != null)
{
//if (!((adornedElement is System.Windows.Shapes.Rectangle) && (((((System.Windows.Shapes.Rectangle)adornedElement))).Tag != null && ((((System.Windows.Shapes.Rectangle)adornedElement))).Tag.ToString() == "CheckBoxGroup")
// || adornedElement is Border && ((Border)adornedElement).Child is CheckBox || (adornedElement is FormDesignerEngine.UserControl.CombControl)))
{
bottomLeft.DragDelta += new DragDeltaEventHandler(HandleBottomLeft);
bottomRight.DragDelta += new DragDeltaEventHandler(HandleBottomRight);
topLeft.DragDelta += new DragDeltaEventHandler(HandleTopLeft);
topRight.DragDelta += new DragDeltaEventHandler(HandleTopRight);
left.DragDelta += new DragDeltaEventHandler(HandleLeft);
right.DragDelta += new DragDeltaEventHandler(HandleRight);
top.DragDelta += new DragDeltaEventHandler(HandleTop);
bottom.DragDelta += new DragDeltaEventHandler(HandleBottom);
}
}
}
private void HandleBottomRight(object sender, DragDeltaEventArgs args)
{
var adornedElement = AdornedElement as FrameworkElement;
var hitThumb = sender as Thumb;
if (adornedElement == null || hitThumb == null)
{
return;
}
EnforceSize(adornedElement);
adornedElement.Width = Math.Max(adornedElement.Width + args.HorizontalChange, hitThumb.DesiredSize.Width);
adornedElement.Height = Math.Max(args.VerticalChange + adornedElement.Height, hitThumb.DesiredSize.Height);
}
private void HandleTopRight(object sender, DragDeltaEventArgs args)
{
var adornedElement = AdornedElement as FrameworkElement;
var hitThumb = sender as Thumb;
if (adornedElement == null || hitThumb == null)
{
return;
}
EnforceSize(adornedElement);
adornedElement.Width = Math.Max(adornedElement.Width + args.HorizontalChange, hitThumb.DesiredSize.Width);
var height_old = adornedElement.Height;
var height_new = Math.Max(adornedElement.Height - args.VerticalChange, hitThumb.DesiredSize.Height);
var top_old = Canvas.GetTop(adornedElement);
adornedElement.Height = height_new;
Canvas.SetTop(adornedElement, top_old - (height_new - height_old));
}
private void HandleTopLeft(object sender, DragDeltaEventArgs args)
{
var adornedElement = AdornedElement as FrameworkElement;
var hitThumb = sender as Thumb;
if (adornedElement == null || hitThumb == null)
{
return;
}
EnforceSize(adornedElement);
var width_old = adornedElement.Width;
var width_new = Math.Max(adornedElement.Width - args.HorizontalChange, hitThumb.DesiredSize.Width);
var left_old = Canvas.GetLeft(adornedElement);
adornedElement.Width = width_new;
Canvas.SetLeft(adornedElement, left_old - (width_new - width_old));
var height_old = adornedElement.Height;
var height_new = Math.Max(adornedElement.Height - args.VerticalChange, hitThumb.DesiredSize.Height);
var top_old = Canvas.GetTop(adornedElement);
adornedElement.Height = height_new;
Canvas.SetTop(adornedElement, top_old - (height_new - height_old));
}
private void HandleBottomLeft(object sender, DragDeltaEventArgs args)
{
var adornedElement = AdornedElement as FrameworkElement;
var hitThumb = sender as Thumb;
if (adornedElement == null || hitThumb == null)
{
return;
}
EnforceSize(adornedElement);
adornedElement.Height = Math.Max(args.VerticalChange + adornedElement.Height, hitThumb.DesiredSize.Height);
var width_old = adornedElement.Width;
var width_new = Math.Max(adornedElement.Width - args.HorizontalChange, hitThumb.DesiredSize.Width);
var left_old = Canvas.GetLeft(adornedElement);
adornedElement.Width = width_new;
Canvas.SetLeft(adornedElement, left_old - (width_new - width_old));
}
private void HandleLeft(object sender, DragDeltaEventArgs args)
{
var adornedElement = AdornedElement as FrameworkElement;
var hitThumb = sender as Thumb;
if (adornedElement == null || hitThumb == null)
{
return;
}
EnforceSize(adornedElement);
var width_old = adornedElement.Width;
var width_new = Math.Max(adornedElement.Width - args.HorizontalChange, hitThumb.DesiredSize.Width);
var left_old = Canvas.GetLeft(adornedElement);
adornedElement.Width = width_new;
Canvas.SetLeft(adornedElement, left_old - (width_new - width_old));
}
private void HandleRight(object sender, DragDeltaEventArgs args)
{
var adornedElement = AdornedElement as FrameworkElement;
var hitThumb = sender as Thumb;
if (adornedElement == null || hitThumb == null)
{
return;
}
EnforceSize(adornedElement);
adornedElement.Width = Math.Max(args.HorizontalChange + adornedElement.Width, hitThumb.DesiredSize.Width);
}
private void HandleBottom(object sender, DragDeltaEventArgs args)
{
var adornedElement = AdornedElement as FrameworkElement;
var hitThumb = sender as Thumb;
if (adornedElement == null || hitThumb == null)
{
return;
}
EnforceSize(adornedElement);
adornedElement.Height = Math.Max(args.VerticalChange + adornedElement.Height, hitThumb.DesiredSize.Height);
}
private void HandleTop(object sender, DragDeltaEventArgs args)
{
var adornedElement = AdornedElement as FrameworkElement;
var hitThumb = sender as Thumb;
if (adornedElement == null || hitThumb == null)
{
return;
}
EnforceSize(adornedElement);
var height_old = adornedElement.Height;
var height_new = Math.Max(adornedElement.Height - args.VerticalChange, hitThumb.DesiredSize.Height);
var top_old = Canvas.GetTop(adornedElement);
adornedElement.Height = height_new;
Canvas.SetTop(adornedElement, top_old - (height_new - height_old));
}
protected override Size ArrangeOverride(Size finalSize)
{
var desiredWidth = AdornedElement.DesiredSize.Width;
var desiredHeight = AdornedElement.DesiredSize.Height;
var adornerWidth = DesiredSize.Width;
var adornerHeight = DesiredSize.Height;
topLeft.Arrange(new Rect(-adornerWidth / 2, -adornerHeight / 2, adornerWidth, adornerHeight));
topRight.Arrange(new Rect(desiredWidth - adornerWidth / 2, -adornerHeight / 2, adornerWidth, adornerHeight));
bottomLeft.Arrange(new Rect(-adornerWidth / 2, desiredHeight - adornerHeight / 2, adornerWidth, adornerHeight));
bottomRight.Arrange(new Rect(desiredWidth - adornerWidth / 2, desiredHeight - adornerHeight / 2, adornerWidth, adornerHeight));
top.Arrange(new Rect(desiredWidth / 2 - adornerWidth / 2, -adornerHeight / 2, adornerWidth, adornerHeight));
bottom.Arrange(new Rect(desiredWidth / 2 - adornerWidth / 2, desiredHeight - adornerHeight / 2, adornerWidth, adornerHeight));
left.Arrange(new Rect(-adornerWidth / 2, desiredHeight / 2 - adornerHeight / 2, adornerWidth, adornerHeight));
right.Arrange(new Rect(desiredWidth - adornerWidth / 2, desiredHeight / 2 - adornerHeight / 2, adornerWidth, adornerHeight));
return finalSize;
}
private void BuildAdornerCorner(ref Thumb cornerThumb, Cursor customizedCursor)
{
if (cornerThumb != null)
{
return;
}
cornerThumb = new Thumb()
{
Cursor = customizedCursor,
Height = Width = 8.5,
Opacity = 0.40,
Background = new SolidColorBrush(Colors.MediumBlue),
};
visualChildren.Add(cornerThumb);
}
private void EnforceSize(FrameworkElement adornedElement)
{
if (adornedElement.Width.Equals(Double.NaN))
{
adornedElement.Width = adornedElement.DesiredSize.Width;
}
if (adornedElement.Height.Equals(Double.NaN))
{
adornedElement.Height = adornedElement.DesiredSize.Height;
}
var parent = adornedElement.Parent as FrameworkElement;
if (parent != null)
{
adornedElement.MaxHeight = parent.ActualHeight;
adornedElement.MaxWidth = parent.ActualWidth;
}
}
protected override int VisualChildrenCount
{
get
{
return visualChildren.Count;
}
}
protected override Visual GetVisualChild(int index)
{
return visualChildren[index];
}
public void ResizeCode()
{
var adornedElement = AdornedElement as FrameworkElement;
adornedElement.Width = adornedElement.Width + 0.1;
adornedElement.Height = adornedElement.Height + 0.1;
}
}
Next, lets create the DragDrop Methods for the canvas in viewModel:
#region global variable
double FirstXPos, FirstYPos, FirstArrowXPos, FirstArrowYPos;
object MovingObject;
Line Path1, Path2, Path3, Path4;
Rectangle FirstPosition, CurrentPosition;
AdornerLayer myAdornerLayer;
#endregion
public void AssignDragDrop(Canvas OptionalDesigningCanvas)
{
/*
* Assigning PreviewMouseLeftButtonDown, PreviewMouseMove and PreviewMouseLeftButtonUp
* events to each controls on our canvas control.
* Some controls events like TextBox's MouseLeftButtonDown doesn't fire, because of that
* we use Preview events.
*/
foreach (Control control in OptionalDesigningCanvas.Children)
{
control.PreviewMouseLeftButtonDown += this.MouseLeftButtonDown;
control.PreviewMouseLeftButtonUp += this.PreviewMouseLeftButtonUp;
control.Cursor = Cursors.Hand;
}
// Setting the MouseMove event for our parent control(In this case it is UpgradeWashBlock).
OptionalDesigningCanvas.PreviewMouseMove += this.MouseMove;
// Setting up the Lines that we want to show the path of movement
List<Double> Dots = new List<double>();
Dots.Add(1);
Dots.Add(2);
Path1 = new Line();
Path1.Width = OptionalDesigningCanvas.Width;
Path1.Height = OptionalDesigningCanvas.Height;
Path1.Stroke = Brushes.DarkGray;
Path1.StrokeDashArray = new DoubleCollection(Dots);
Path2 = new Line();
Path2.Width = OptionalDesigningCanvas.Width;
Path2.Height = OptionalDesigningCanvas.Height;
Path2.Stroke = Brushes.DarkGray;
Path2.StrokeDashArray = new DoubleCollection(Dots);
Path3 = new Line();
Path3.Width = OptionalDesigningCanvas.Width;
Path3.Height = OptionalDesigningCanvas.Height;
Path3.Stroke = Brushes.DarkGray;
Path3.StrokeDashArray = new DoubleCollection(Dots);
Path4 = new Line();
Path4.Width = OptionalDesigningCanvas.Width;
Path4.Height = OptionalDesigningCanvas.Height;
Path4.Stroke = Brushes.DarkGray;
Path4.StrokeDashArray = new DoubleCollection(Dots);
FirstPosition = new Rectangle();
FirstPosition.Stroke = Brushes.DarkGray;
FirstPosition.StrokeDashArray = new DoubleCollection(Dots);
CurrentPosition = new Rectangle();
CurrentPosition.Stroke = Brushes.DarkGray;
CurrentPosition.StrokeDashArray = new DoubleCollection(Dots);
// Adding Lines to main designing panel(Canvas)
OptionalDesigningCanvas.Children.Add(Path1);
OptionalDesigningCanvas.Children.Add(Path2);
OptionalDesigningCanvas.Children.Add(Path3);
OptionalDesigningCanvas.Children.Add(Path4);
OptionalDesigningCanvas.Children.Add(FirstPosition);
OptionalDesigningCanvas.Children.Add(CurrentPosition);
}
private void PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
// In this event, we should set the lines visibility to Hidden
MovingObject = null;
Path1.Visibility = System.Windows.Visibility.Hidden;
Path2.Visibility = System.Windows.Visibility.Hidden;
Path3.Visibility = System.Windows.Visibility.Hidden;
Path4.Visibility = System.Windows.Visibility.Hidden;
FirstPosition.Visibility = System.Windows.Visibility.Hidden;
CurrentPosition.Visibility = System.Windows.Visibility.Hidden;
}
private void MouseMove(object sender, MouseEventArgs e)
{
/*
* In this event, at first we check the mouse left button state. If it is pressed and
* event sender object is similar with our moving object, we can move our control with
* some effects.
*/
try
{
if (e.LeftButton == MouseButtonState.Pressed)
{
// We start to moving objects with setting the lines positions.
Path1.X1 = FirstArrowXPos;
Path1.Y1 = FirstArrowYPos;
Path1.X2 = e.GetPosition((MovingObject as FrameworkElement).Parent as FrameworkElement).X - FirstXPos;
Path1.Y2 = e.GetPosition((MovingObject as FrameworkElement).Parent as FrameworkElement).Y - FirstYPos;
Path2.X1 = Path1.X1 + (MovingObject as FrameworkElement).ActualWidth;
Path2.Y1 = Path1.Y1;
Path2.X2 = Path1.X2 + (MovingObject as FrameworkElement).ActualWidth;
Path2.Y2 = Path1.Y2;
Path3.X1 = Path1.X1;
Path3.Y1 = Path1.Y1 + (MovingObject as FrameworkElement).ActualHeight;
Path3.X2 = Path1.X2;
Path3.Y2 = Path1.Y2 + (MovingObject as FrameworkElement).ActualHeight;
Path4.X1 = Path1.X1 + (MovingObject as FrameworkElement).ActualWidth;
Path4.Y1 = Path1.Y1 + (MovingObject as FrameworkElement).ActualHeight;
Path4.X2 = Path1.X2 + (MovingObject as FrameworkElement).ActualWidth;
Path4.Y2 = Path1.Y2 + (MovingObject as FrameworkElement).ActualHeight;
FirstPosition.Width = (MovingObject as FrameworkElement).ActualWidth;
FirstPosition.Height = (MovingObject as FrameworkElement).ActualHeight;
FirstPosition.SetValue(Canvas.LeftProperty, FirstArrowXPos);
FirstPosition.SetValue(Canvas.TopProperty, FirstArrowYPos);
CurrentPosition.Width = (MovingObject as FrameworkElement).ActualWidth;
CurrentPosition.Height = (MovingObject as FrameworkElement).ActualHeight;
CurrentPosition.SetValue(Canvas.LeftProperty, Path1.X2);
CurrentPosition.SetValue(Canvas.TopProperty, Path1.Y2);
Path1.Visibility = System.Windows.Visibility.Visible;
Path2.Visibility = System.Windows.Visibility.Visible;
Path3.Visibility = System.Windows.Visibility.Visible;
Path4.Visibility = System.Windows.Visibility.Visible;
FirstPosition.Visibility = System.Windows.Visibility.Visible;
CurrentPosition.Visibility = System.Windows.Visibility.Visible;
/*
* For changing the position of a control, we should use the SetValue method to setting
* the Canvas.LeftProperty and Canvas.TopProperty dependencies.
*
* For calculating the currect position of the control, we should do :
* Current position of the mouse cursor on the object parent -
* Mouse position on the control at the start of moving -
* position of the control's parent.
*/
(MovingObject as FrameworkElement).SetValue(Canvas.LeftProperty,
e.GetPosition((MovingObject as FrameworkElement).Parent as FrameworkElement).X - FirstXPos);
(MovingObject as FrameworkElement).SetValue(Canvas.TopProperty,
e.GetPosition((MovingObject as FrameworkElement).Parent as FrameworkElement).Y - FirstYPos);
//if (ctrl != null)
//{
// ctrl.ResizeCode();
//}
}
}
catch
{
}
}
private void MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
SetObjectProperties(sender);
//In this event, we get current mouse position on the control to use it in the MouseMove event.
FirstXPos = e.GetPosition(sender as Control).X;
FirstYPos = e.GetPosition(sender as Control).Y;
FirstArrowXPos = e.GetPosition((sender as Control).Parent as Control).X - FirstXPos;
FirstArrowYPos = e.GetPosition((sender as Control).Parent as Control).Y - FirstYPos;
MovingObject = sender;
}
ResizingAdorner ctrl;
private void SetObjectProperties(object sender)
{
if (sender is TextBox)
{
TextBox txt = (TextBox)sender;
myAdornerLayer = AdornerLayer.GetAdornerLayer(txt);
myAdornerLayer.Add(new ResizingAdorner(txt));
}
else if (sender is Image)
{
//Washify.UserControlNew.ReDesignUserControl.LogoResizeUserControl txt = (Washify.UserControlNew.ReDesignUserControl.LogoResizeUserControl)sender;
Image txt = (Image)sender;
myAdornerLayer = AdornerLayer.GetAdornerLayer(txt);
ctrl = new ResizingAdorner(txt);
myAdornerLayer.Add(ctrl);
}
else if (sender is UserControl)
{
//Washify.UserControlNew.ReDesignUserControl.LogoResizeUserControl txt = (Washify.UserControlNew.ReDesignUserControl.LogoResizeUserControl)sender;
UserControl txt = (UserControl)sender;
myAdornerLayer = AdornerLayer.GetAdornerLayer(txt);
ctrl = new ResizingAdorner(txt);
myAdornerLayer.Add(ctrl);
}
else if (sender is ContentControl)
{
//Washify.UserControlNew.ReDesignUserControl.LogoResizeUserControl txt = (Washify.UserControlNew.ReDesignUserControl.LogoResizeUserControl)sender;
ContentControl txt = (ContentControl)sender;
myAdornerLayer = AdornerLayer.GetAdornerLayer(txt);
ctrl = new ResizingAdorner(txt);
myAdornerLayer.Add(ctrl);
}
else if (sender is Button)
{
Button txt = (Button)sender;
myAdornerLayer = AdornerLayer.GetAdornerLayer(txt);
myAdornerLayer.Add(new ResizingAdorner(txt));
}
}
Step 9: Now lets get the positions and save them wherever you want to:
First you need to add a save button on MainWindow, on clicking that button we will be fetching the positions and save them:
private RelayCommand<Canvas> saveCommand;
public RelayCommand<Canvas> SaveCommand
{
get
{
return saveCommand ?? (saveCommand = new RelayCommand<Canvas>(x => Save(x)));
}
}
/// <summary>
/// Save the position and size of service blocks.
/// </summary>
/// <param name="canvasControl"></param>
private void Save(Canvas canvasControl)
{
synchronizationContext = SynchronizationContext.Current;
try
{
RedesignServices RedesignServices = new RedesignServices();
foreach (var resizedControl in canvasControl.Children)
{
if (resizedControl.GetType().Name == " TextBoxtoresize")
{
TextBox resizedControl1 = (TextBox)resizedControl;
Int32 left, top; double height, width;
string value = resizedControl1.GetValue(Canvas.LeftProperty).ToString().Trim();
Int32.TryParse(value, out left);
value = resizedControl1.GetValue(Canvas.TopProperty).ToString().Trim();
Int32.TryParse(value, out top);
string valueHeight = resizedControl1.GetValue(Canvas.HeightProperty).ToString().Trim();
height = Convert.ToDouble(valueHeight);
string valuewidth = resizedControl1.GetValue(Canvas.WidthProperty).ToString().Trim();
width = Convert.ToDouble(valuewidth);
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Thats it, now we are ready to run the application to see the results:
As Controls get the positions from their immediate parent canvas. So we will not be using Itemcontrol to display the controls so that canvas can have full control on the children(the controls that needs to get resized and reposition)
Below are the steps we need to follow for this:
Step 1: Lets use the same MainWindow and add a canvas control to it.The xaml for MainWindow.xaml should look like as below:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Canvas x:Name="DesigningCanvas" >
</Canvas>
</Grid>
Step 2:Lets Create a list containing the positions of controls and let bind that to the canvas children.
Step 3: Lets Create a class under ViewModel folder only named as “ControlDetails”, Class should look like:
namespace WpfApplication1.ViewModel
{
public class ControlDetails
{
public double Height
{
get;
set;
}
public double Width
{
get;
set;
}
public double Top
{
get;
set;
}
public double Left
{
get;
set;
}
}
}
Step 4: Lets go to the MainWindowViewModel and add the records into the ControlDetailsList to bind the ItemControl and to define the position of controls.
public void AddControlPositionToList()
{
controlDetailsList = new List<ControlDetails>();
ControlDetails controlDetails = new ControlDetails();
controlDetails.Height = 100;
controlDetails.Width = 200;
controlDetails.Left = 164;
controlDetails.Top = 86;
controlDetailsList.Add(controlDetails);
controlDetails = new ControlDetails();
controlDetails.Height = 200;
controlDetails.Width = 300;
controlDetails.Left = 349;
controlDetails.Top = 100;
controlDetailsList.Add(controlDetails);
controlDetails = new ControlDetails();
controlDetails.Height = 300;
controlDetails.Width = 400;
controlDetails.Left = 558;
controlDetails.Top = 40;
controlDetailsList.Add(controlDetails);
controlDetails = new ControlDetails();
controlDetails.Height = 400;
controlDetails.Width = 500;
controlDetails.Left = 733;
controlDetails.Top = 40;
controlDetailsList.Add(controlDetails);
}
So in above records we have defined the Height and width of the controls and Top and left margins or positions of the controls.
Step 5: Lets call this list in the IntitializeCollections or constructor where ever you want to bind the Itemcontrol.
public MainWindowViewModel()
{
AddControlPositionToList();
}
Step 6: Now lets bind the canvas children, that we need to do in MainWindow.cs.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
MainWindowViewModel mainWindowViewModel = new MainWindowViewModel();
this.DataContext = mainWindowViewModel;
BindCanvas(mainWindowViewModel);
}
public void BindCanvas(MainWindowViewModel mainWindowViewModel)
{
foreach (var details in mainWindowViewModel.controlDetailsList)
{
TextBox textBox = new TextBox();
if (details.Top >= 0)
textBox.SetValue(Canvas.TopProperty, Convert.ToDouble(details.Top));
if (details.Left >= 0)
textBox.SetValue(Canvas.LeftProperty, Convert.ToDouble(details.Left));
if (details.Height >= 0)
textBox.Height = details.Height;
if (details.Width >= 0)
textBox.Width = details.Width;
DesigningCanvas.Children.Add(textBox);
}
}
}
Now the above method binds the textbox as the canvas children and also assigns the positions already defined for the control in list.
Step 7:
Now to change the positions by drag drop the controls, we need to set the drag and drop points on t he canvas children, so now to access the canvas and its children from the MainWindowViewModel, we need to send the canvas control as the command parameter, so for that we are going to use Loaded event command.
As soon as our page and canvas would completes loaing that event should get fired.
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding LoadCommand}"
CommandParameter="{Binding ElementName=DesigningCanvas}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
Lets create the RelayCommand for Load Event in MainWindowViewModel.cs
private RelayCommand<Canvas> loadCommand;
public RelayCommand<Canvas> LoadCommand
{
get
{
return loadCommand ?? (loadCommand = new RelayCommand<Canvas>(x => AssignDragDrop(x)));
}
}
Step 8:
Lets now Create a Method to Assign Drag Drop positions to the Canvas Children but before doing that lets add a class for Adorner resizing , defining all the methods needs to resize the controls.So the ResizingAdorner should look like as below:
public class ResizingAdorner : Adorner
{
private readonly Thumb topLeft, topRight, bottomLeft, bottomRight, left, top, right, bottom;
private readonly VisualCollection visualChildren;
public ResizingAdorner(UIElement adornedElement)
: base(adornedElement)
{
visualChildren = new VisualCollection(this);
BuildAdornerCorner(ref topLeft, Cursors.SizeNWSE);
BuildAdornerCorner(ref topRight, Cursors.SizeNESW);
BuildAdornerCorner(ref bottomLeft, Cursors.SizeNESW);
BuildAdornerCorner(ref bottomRight, Cursors.SizeNWSE);
BuildAdornerCorner(ref left, Cursors.SizeWE);
BuildAdornerCorner(ref top, Cursors.SizeNS);
BuildAdornerCorner(ref right, Cursors.SizeWE);
BuildAdornerCorner(ref bottom, Cursors.SizeNS);
//CheckBox and CheckBoxGroup shouldn't resize
if (adornedElement != null)
{
//if (!((adornedElement is System.Windows.Shapes.Rectangle) && (((((System.Windows.Shapes.Rectangle)adornedElement))).Tag != null && ((((System.Windows.Shapes.Rectangle)adornedElement))).Tag.ToString() == "CheckBoxGroup")
// || adornedElement is Border && ((Border)adornedElement).Child is CheckBox || (adornedElement is FormDesignerEngine.UserControl.CombControl)))
{
bottomLeft.DragDelta += new DragDeltaEventHandler(HandleBottomLeft);
bottomRight.DragDelta += new DragDeltaEventHandler(HandleBottomRight);
topLeft.DragDelta += new DragDeltaEventHandler(HandleTopLeft);
topRight.DragDelta += new DragDeltaEventHandler(HandleTopRight);
left.DragDelta += new DragDeltaEventHandler(HandleLeft);
right.DragDelta += new DragDeltaEventHandler(HandleRight);
top.DragDelta += new DragDeltaEventHandler(HandleTop);
bottom.DragDelta += new DragDeltaEventHandler(HandleBottom);
}
}
}
private void HandleBottomRight(object sender, DragDeltaEventArgs args)
{
var adornedElement = AdornedElement as FrameworkElement;
var hitThumb = sender as Thumb;
if (adornedElement == null || hitThumb == null)
{
return;
}
EnforceSize(adornedElement);
adornedElement.Width = Math.Max(adornedElement.Width + args.HorizontalChange, hitThumb.DesiredSize.Width);
adornedElement.Height = Math.Max(args.VerticalChange + adornedElement.Height, hitThumb.DesiredSize.Height);
}
private void HandleTopRight(object sender, DragDeltaEventArgs args)
{
var adornedElement = AdornedElement as FrameworkElement;
var hitThumb = sender as Thumb;
if (adornedElement == null || hitThumb == null)
{
return;
}
EnforceSize(adornedElement);
adornedElement.Width = Math.Max(adornedElement.Width + args.HorizontalChange, hitThumb.DesiredSize.Width);
var height_old = adornedElement.Height;
var height_new = Math.Max(adornedElement.Height - args.VerticalChange, hitThumb.DesiredSize.Height);
var top_old = Canvas.GetTop(adornedElement);
adornedElement.Height = height_new;
Canvas.SetTop(adornedElement, top_old - (height_new - height_old));
}
private void HandleTopLeft(object sender, DragDeltaEventArgs args)
{
var adornedElement = AdornedElement as FrameworkElement;
var hitThumb = sender as Thumb;
if (adornedElement == null || hitThumb == null)
{
return;
}
EnforceSize(adornedElement);
var width_old = adornedElement.Width;
var width_new = Math.Max(adornedElement.Width - args.HorizontalChange, hitThumb.DesiredSize.Width);
var left_old = Canvas.GetLeft(adornedElement);
adornedElement.Width = width_new;
Canvas.SetLeft(adornedElement, left_old - (width_new - width_old));
var height_old = adornedElement.Height;
var height_new = Math.Max(adornedElement.Height - args.VerticalChange, hitThumb.DesiredSize.Height);
var top_old = Canvas.GetTop(adornedElement);
adornedElement.Height = height_new;
Canvas.SetTop(adornedElement, top_old - (height_new - height_old));
}
private void HandleBottomLeft(object sender, DragDeltaEventArgs args)
{
var adornedElement = AdornedElement as FrameworkElement;
var hitThumb = sender as Thumb;
if (adornedElement == null || hitThumb == null)
{
return;
}
EnforceSize(adornedElement);
adornedElement.Height = Math.Max(args.VerticalChange + adornedElement.Height, hitThumb.DesiredSize.Height);
var width_old = adornedElement.Width;
var width_new = Math.Max(adornedElement.Width - args.HorizontalChange, hitThumb.DesiredSize.Width);
var left_old = Canvas.GetLeft(adornedElement);
adornedElement.Width = width_new;
Canvas.SetLeft(adornedElement, left_old - (width_new - width_old));
}
private void HandleLeft(object sender, DragDeltaEventArgs args)
{
var adornedElement = AdornedElement as FrameworkElement;
var hitThumb = sender as Thumb;
if (adornedElement == null || hitThumb == null)
{
return;
}
EnforceSize(adornedElement);
var width_old = adornedElement.Width;
var width_new = Math.Max(adornedElement.Width - args.HorizontalChange, hitThumb.DesiredSize.Width);
var left_old = Canvas.GetLeft(adornedElement);
adornedElement.Width = width_new;
Canvas.SetLeft(adornedElement, left_old - (width_new - width_old));
}
private void HandleRight(object sender, DragDeltaEventArgs args)
{
var adornedElement = AdornedElement as FrameworkElement;
var hitThumb = sender as Thumb;
if (adornedElement == null || hitThumb == null)
{
return;
}
EnforceSize(adornedElement);
adornedElement.Width = Math.Max(args.HorizontalChange + adornedElement.Width, hitThumb.DesiredSize.Width);
}
private void HandleBottom(object sender, DragDeltaEventArgs args)
{
var adornedElement = AdornedElement as FrameworkElement;
var hitThumb = sender as Thumb;
if (adornedElement == null || hitThumb == null)
{
return;
}
EnforceSize(adornedElement);
adornedElement.Height = Math.Max(args.VerticalChange + adornedElement.Height, hitThumb.DesiredSize.Height);
}
private void HandleTop(object sender, DragDeltaEventArgs args)
{
var adornedElement = AdornedElement as FrameworkElement;
var hitThumb = sender as Thumb;
if (adornedElement == null || hitThumb == null)
{
return;
}
EnforceSize(adornedElement);
var height_old = adornedElement.Height;
var height_new = Math.Max(adornedElement.Height - args.VerticalChange, hitThumb.DesiredSize.Height);
var top_old = Canvas.GetTop(adornedElement);
adornedElement.Height = height_new;
Canvas.SetTop(adornedElement, top_old - (height_new - height_old));
}
protected override Size ArrangeOverride(Size finalSize)
{
var desiredWidth = AdornedElement.DesiredSize.Width;
var desiredHeight = AdornedElement.DesiredSize.Height;
var adornerWidth = DesiredSize.Width;
var adornerHeight = DesiredSize.Height;
topLeft.Arrange(new Rect(-adornerWidth / 2, -adornerHeight / 2, adornerWidth, adornerHeight));
topRight.Arrange(new Rect(desiredWidth - adornerWidth / 2, -adornerHeight / 2, adornerWidth, adornerHeight));
bottomLeft.Arrange(new Rect(-adornerWidth / 2, desiredHeight - adornerHeight / 2, adornerWidth, adornerHeight));
bottomRight.Arrange(new Rect(desiredWidth - adornerWidth / 2, desiredHeight - adornerHeight / 2, adornerWidth, adornerHeight));
top.Arrange(new Rect(desiredWidth / 2 - adornerWidth / 2, -adornerHeight / 2, adornerWidth, adornerHeight));
bottom.Arrange(new Rect(desiredWidth / 2 - adornerWidth / 2, desiredHeight - adornerHeight / 2, adornerWidth, adornerHeight));
left.Arrange(new Rect(-adornerWidth / 2, desiredHeight / 2 - adornerHeight / 2, adornerWidth, adornerHeight));
right.Arrange(new Rect(desiredWidth - adornerWidth / 2, desiredHeight / 2 - adornerHeight / 2, adornerWidth, adornerHeight));
return finalSize;
}
private void BuildAdornerCorner(ref Thumb cornerThumb, Cursor customizedCursor)
{
if (cornerThumb != null)
{
return;
}
cornerThumb = new Thumb()
{
Cursor = customizedCursor,
Height = Width = 8.5,
Opacity = 0.40,
Background = new SolidColorBrush(Colors.MediumBlue),
};
visualChildren.Add(cornerThumb);
}
private void EnforceSize(FrameworkElement adornedElement)
{
if (adornedElement.Width.Equals(Double.NaN))
{
adornedElement.Width = adornedElement.DesiredSize.Width;
}
if (adornedElement.Height.Equals(Double.NaN))
{
adornedElement.Height = adornedElement.DesiredSize.Height;
}
var parent = adornedElement.Parent as FrameworkElement;
if (parent != null)
{
adornedElement.MaxHeight = parent.ActualHeight;
adornedElement.MaxWidth = parent.ActualWidth;
}
}
protected override int VisualChildrenCount
{
get
{
return visualChildren.Count;
}
}
protected override Visual GetVisualChild(int index)
{
return visualChildren[index];
}
public void ResizeCode()
{
var adornedElement = AdornedElement as FrameworkElement;
adornedElement.Width = adornedElement.Width + 0.1;
adornedElement.Height = adornedElement.Height + 0.1;
}
}
Next, lets create the DragDrop Methods for the canvas in viewModel:
#region global variable
double FirstXPos, FirstYPos, FirstArrowXPos, FirstArrowYPos;
object MovingObject;
Line Path1, Path2, Path3, Path4;
Rectangle FirstPosition, CurrentPosition;
AdornerLayer myAdornerLayer;
#endregion
public void AssignDragDrop(Canvas OptionalDesigningCanvas)
{
/*
* Assigning PreviewMouseLeftButtonDown, PreviewMouseMove and PreviewMouseLeftButtonUp
* events to each controls on our canvas control.
* Some controls events like TextBox's MouseLeftButtonDown doesn't fire, because of that
* we use Preview events.
*/
foreach (Control control in OptionalDesigningCanvas.Children)
{
control.PreviewMouseLeftButtonDown += this.MouseLeftButtonDown;
control.PreviewMouseLeftButtonUp += this.PreviewMouseLeftButtonUp;
control.Cursor = Cursors.Hand;
}
// Setting the MouseMove event for our parent control(In this case it is UpgradeWashBlock).
OptionalDesigningCanvas.PreviewMouseMove += this.MouseMove;
// Setting up the Lines that we want to show the path of movement
List<Double> Dots = new List<double>();
Dots.Add(1);
Dots.Add(2);
Path1 = new Line();
Path1.Width = OptionalDesigningCanvas.Width;
Path1.Height = OptionalDesigningCanvas.Height;
Path1.Stroke = Brushes.DarkGray;
Path1.StrokeDashArray = new DoubleCollection(Dots);
Path2 = new Line();
Path2.Width = OptionalDesigningCanvas.Width;
Path2.Height = OptionalDesigningCanvas.Height;
Path2.Stroke = Brushes.DarkGray;
Path2.StrokeDashArray = new DoubleCollection(Dots);
Path3 = new Line();
Path3.Width = OptionalDesigningCanvas.Width;
Path3.Height = OptionalDesigningCanvas.Height;
Path3.Stroke = Brushes.DarkGray;
Path3.StrokeDashArray = new DoubleCollection(Dots);
Path4 = new Line();
Path4.Width = OptionalDesigningCanvas.Width;
Path4.Height = OptionalDesigningCanvas.Height;
Path4.Stroke = Brushes.DarkGray;
Path4.StrokeDashArray = new DoubleCollection(Dots);
FirstPosition = new Rectangle();
FirstPosition.Stroke = Brushes.DarkGray;
FirstPosition.StrokeDashArray = new DoubleCollection(Dots);
CurrentPosition = new Rectangle();
CurrentPosition.Stroke = Brushes.DarkGray;
CurrentPosition.StrokeDashArray = new DoubleCollection(Dots);
// Adding Lines to main designing panel(Canvas)
OptionalDesigningCanvas.Children.Add(Path1);
OptionalDesigningCanvas.Children.Add(Path2);
OptionalDesigningCanvas.Children.Add(Path3);
OptionalDesigningCanvas.Children.Add(Path4);
OptionalDesigningCanvas.Children.Add(FirstPosition);
OptionalDesigningCanvas.Children.Add(CurrentPosition);
}
private void PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
// In this event, we should set the lines visibility to Hidden
MovingObject = null;
Path1.Visibility = System.Windows.Visibility.Hidden;
Path2.Visibility = System.Windows.Visibility.Hidden;
Path3.Visibility = System.Windows.Visibility.Hidden;
Path4.Visibility = System.Windows.Visibility.Hidden;
FirstPosition.Visibility = System.Windows.Visibility.Hidden;
CurrentPosition.Visibility = System.Windows.Visibility.Hidden;
}
private void MouseMove(object sender, MouseEventArgs e)
{
/*
* In this event, at first we check the mouse left button state. If it is pressed and
* event sender object is similar with our moving object, we can move our control with
* some effects.
*/
try
{
if (e.LeftButton == MouseButtonState.Pressed)
{
// We start to moving objects with setting the lines positions.
Path1.X1 = FirstArrowXPos;
Path1.Y1 = FirstArrowYPos;
Path1.X2 = e.GetPosition((MovingObject as FrameworkElement).Parent as FrameworkElement).X - FirstXPos;
Path1.Y2 = e.GetPosition((MovingObject as FrameworkElement).Parent as FrameworkElement).Y - FirstYPos;
Path2.X1 = Path1.X1 + (MovingObject as FrameworkElement).ActualWidth;
Path2.Y1 = Path1.Y1;
Path2.X2 = Path1.X2 + (MovingObject as FrameworkElement).ActualWidth;
Path2.Y2 = Path1.Y2;
Path3.X1 = Path1.X1;
Path3.Y1 = Path1.Y1 + (MovingObject as FrameworkElement).ActualHeight;
Path3.X2 = Path1.X2;
Path3.Y2 = Path1.Y2 + (MovingObject as FrameworkElement).ActualHeight;
Path4.X1 = Path1.X1 + (MovingObject as FrameworkElement).ActualWidth;
Path4.Y1 = Path1.Y1 + (MovingObject as FrameworkElement).ActualHeight;
Path4.X2 = Path1.X2 + (MovingObject as FrameworkElement).ActualWidth;
Path4.Y2 = Path1.Y2 + (MovingObject as FrameworkElement).ActualHeight;
FirstPosition.Width = (MovingObject as FrameworkElement).ActualWidth;
FirstPosition.Height = (MovingObject as FrameworkElement).ActualHeight;
FirstPosition.SetValue(Canvas.LeftProperty, FirstArrowXPos);
FirstPosition.SetValue(Canvas.TopProperty, FirstArrowYPos);
CurrentPosition.Width = (MovingObject as FrameworkElement).ActualWidth;
CurrentPosition.Height = (MovingObject as FrameworkElement).ActualHeight;
CurrentPosition.SetValue(Canvas.LeftProperty, Path1.X2);
CurrentPosition.SetValue(Canvas.TopProperty, Path1.Y2);
Path1.Visibility = System.Windows.Visibility.Visible;
Path2.Visibility = System.Windows.Visibility.Visible;
Path3.Visibility = System.Windows.Visibility.Visible;
Path4.Visibility = System.Windows.Visibility.Visible;
FirstPosition.Visibility = System.Windows.Visibility.Visible;
CurrentPosition.Visibility = System.Windows.Visibility.Visible;
/*
* For changing the position of a control, we should use the SetValue method to setting
* the Canvas.LeftProperty and Canvas.TopProperty dependencies.
*
* For calculating the currect position of the control, we should do :
* Current position of the mouse cursor on the object parent -
* Mouse position on the control at the start of moving -
* position of the control's parent.
*/
(MovingObject as FrameworkElement).SetValue(Canvas.LeftProperty,
e.GetPosition((MovingObject as FrameworkElement).Parent as FrameworkElement).X - FirstXPos);
(MovingObject as FrameworkElement).SetValue(Canvas.TopProperty,
e.GetPosition((MovingObject as FrameworkElement).Parent as FrameworkElement).Y - FirstYPos);
//if (ctrl != null)
//{
// ctrl.ResizeCode();
//}
}
}
catch
{
}
}
private void MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
SetObjectProperties(sender);
//In this event, we get current mouse position on the control to use it in the MouseMove event.
FirstXPos = e.GetPosition(sender as Control).X;
FirstYPos = e.GetPosition(sender as Control).Y;
FirstArrowXPos = e.GetPosition((sender as Control).Parent as Control).X - FirstXPos;
FirstArrowYPos = e.GetPosition((sender as Control).Parent as Control).Y - FirstYPos;
MovingObject = sender;
}
ResizingAdorner ctrl;
private void SetObjectProperties(object sender)
{
if (sender is TextBox)
{
TextBox txt = (TextBox)sender;
myAdornerLayer = AdornerLayer.GetAdornerLayer(txt);
myAdornerLayer.Add(new ResizingAdorner(txt));
}
else if (sender is Image)
{
//Washify.UserControlNew.ReDesignUserControl.LogoResizeUserControl txt = (Washify.UserControlNew.ReDesignUserControl.LogoResizeUserControl)sender;
Image txt = (Image)sender;
myAdornerLayer = AdornerLayer.GetAdornerLayer(txt);
ctrl = new ResizingAdorner(txt);
myAdornerLayer.Add(ctrl);
}
else if (sender is UserControl)
{
//Washify.UserControlNew.ReDesignUserControl.LogoResizeUserControl txt = (Washify.UserControlNew.ReDesignUserControl.LogoResizeUserControl)sender;
UserControl txt = (UserControl)sender;
myAdornerLayer = AdornerLayer.GetAdornerLayer(txt);
ctrl = new ResizingAdorner(txt);
myAdornerLayer.Add(ctrl);
}
else if (sender is ContentControl)
{
//Washify.UserControlNew.ReDesignUserControl.LogoResizeUserControl txt = (Washify.UserControlNew.ReDesignUserControl.LogoResizeUserControl)sender;
ContentControl txt = (ContentControl)sender;
myAdornerLayer = AdornerLayer.GetAdornerLayer(txt);
ctrl = new ResizingAdorner(txt);
myAdornerLayer.Add(ctrl);
}
else if (sender is Button)
{
Button txt = (Button)sender;
myAdornerLayer = AdornerLayer.GetAdornerLayer(txt);
myAdornerLayer.Add(new ResizingAdorner(txt));
}
}
Step 9: Now lets get the positions and save them wherever you want to:
First you need to add a save button on MainWindow, on clicking that button we will be fetching the positions and save them:
private RelayCommand<Canvas> saveCommand;
public RelayCommand<Canvas> SaveCommand
{
get
{
return saveCommand ?? (saveCommand = new RelayCommand<Canvas>(x => Save(x)));
}
}
/// <summary>
/// Save the position and size of service blocks.
/// </summary>
/// <param name="canvasControl"></param>
private void Save(Canvas canvasControl)
{
synchronizationContext = SynchronizationContext.Current;
try
{
RedesignServices RedesignServices = new RedesignServices();
foreach (var resizedControl in canvasControl.Children)
{
if (resizedControl.GetType().Name == " TextBoxtoresize")
{
TextBox resizedControl1 = (TextBox)resizedControl;
Int32 left, top; double height, width;
string value = resizedControl1.GetValue(Canvas.LeftProperty).ToString().Trim();
Int32.TryParse(value, out left);
value = resizedControl1.GetValue(Canvas.TopProperty).ToString().Trim();
Int32.TryParse(value, out top);
string valueHeight = resizedControl1.GetValue(Canvas.HeightProperty).ToString().Trim();
height = Convert.ToDouble(valueHeight);
string valuewidth = resizedControl1.GetValue(Canvas.WidthProperty).ToString().Trim();
width = Convert.ToDouble(valuewidth);
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Thats it, now we are ready to run the application to see the results:
Comments
Post a Comment