I keep seeing posts about adding Events to be able to drag around the panel. But how would i achieve this through a dynamically created Panel?
Panel pn = wch.GenerateWorkspaceControl(space.Name, space.Name, p);
PanelTest.Controls.Add(pn);
public Panel GenerateWorkspaceControl(string gbTitle, string gbName, Point gbPos)
{
Panel pnl = GeneratePanelContainer(gbPos, new Size(300, 200));
pnl.Controls.Add(GenerateLabel(gbName,new Point(100,1),new Size(135,115)));
return pnl;
}
private Panel GeneratePanelContainer(Point loc, Size size)
{
return new Panel() { BackColor = Color.Transparent, BorderStyle = BorderStyle.FixedSingle, Location = loc, Size = size };
}
Do i add an event handler in the generate panel container?
to summarize i have a panel that is holding multiple panels that are dynamically created. I want to be able to move around the dynmaically created panels INSIDE the main panel.
Any ideas?
Here is a class that lets you make any control movable.
Simply register it:
MoveController.RegisterCtl( button1 );
Now you can move the control..
When done you can also unregister a control:
MoveController.UnRegisterCtl( button1 );
Here is the controller class:
static class MoveController
{
static List<Control> Controls = new List<Control>();
static Control curCtl = null;
static Point curStart = Point.Empty;
static public void RegisterCtl(Control ctl)
{
Controls.Add(ctl);
ctl.MouseDown += ctl_MouseDown;
ctl.MouseMove += ctl_MouseMove;
ctl.MouseUp += ctl_MouseUp;
}
static public void UnRegisterCtl(Control ctl)
{
if (Controls != null && Controls.Contains(ctl) )
{
Controls.Remove(ctl);
ctl.MouseDown -= ctl_MouseDown;
ctl.MouseMove -= ctl_MouseMove;
ctl.MouseUp -= ctl_MouseUp;
}
}
static void ctl_MouseDown(object sender, MouseEventArgs e)
{
curCtl = (Control)sender;
curStart = curCtl.Location;
}
static void ctl_MouseMove(object sender, MouseEventArgs e)
{
if (curCtl != null)
{
curCtl.Left += e.Location.X - curCtl.Width / 2;
curCtl.Top += e.Location.Y - curCtl.Height / 2;
}
}
static void ctl_MouseUp(object sender, MouseEventArgs e)
{
curCtl = null;
}
}
Update
Here is a more involved version that allows
to set a Tag value to restrict movement to vertical or horizontal
adding Actions for Moving and Moved events..
class MoveController
{
static List<Control> Controls = new List<Control>();
static Control curCtl = null;
static Point curStart = Point.Empty;
static Dictionary<Control, Tuple<Action, Action>>
actions = new Dictionary<Control, Tuple<Action, Action>>();
static public void RegisterCtl(Control ctl)
{
RegisterCtl(ctl, null, null);
}
static public void RegisterCtl(Control ctl, Action moveAction, Action movedAction)
{
Controls.Add(ctl);
ctl.MouseEnter += Ctl_MouseEnter;
ctl.MouseLeave += Ctl_MouseLeave;
ctl.MouseDown += ctl_MouseDown;
ctl.MouseMove += ctl_MouseMove;
ctl.MouseUp += ctl_MouseUp;
if (moveAction != null)
if (actions.Keys.Contains(ctl)) actions[ctl] = new Tuple<Action, Action>(moveAction, movedAction);
else actions.Add(ctl, new Tuple<Action, Action>(moveAction, movedAction));
}
private static void Ctl_MouseEnter(object sender, EventArgs e)
{
((Control)sender).Cursor = Cursors.Hand;
}
private static void Ctl_MouseLeave(object sender, EventArgs e)
{
((Control)sender).Cursor = Cursors.Default;
}
public static void UnRegisterCtl(Control ctl)
{
if (Controls != null && Controls.Contains(ctl) )
{
Controls.Remove(ctl);
ctl.MouseDown -= ctl_MouseDown;
ctl.MouseMove -= ctl_MouseMove;
ctl.MouseUp -= ctl_MouseUp;
}
if (actions.ContainsKey(ctl)) actions.Remove(ctl);
}
static public void RegisterMovingAction(Control ctl, Action action)
{
}
static void ctl_MouseDown(object sender, MouseEventArgs e)
{
curCtl = (Control)sender;
curStart = curCtl.Location;
}
static void ctl_MouseMove(object sender, MouseEventArgs e)
{
int t = 0;
if (curCtl != null)
{
if (curCtl.Tag != null) t = Convert.ToInt32(curCtl.Tag);
if ((t&1) != 1) curCtl.Left += e.Location.X - curCtl.Width / 2;
if ((t&2) != 2) curCtl.Top += e.Location.Y - curCtl.Height / 2;
if (actions.ContainsKey(curCtl) && actions[curCtl] != null && actions[curCtl].Item1 != null)
actions[curCtl].Item1();
}
}
static void ctl_MouseUp(object sender, MouseEventArgs e)
{
if (curCtl == null) return; ///
if (actions.ContainsKey(curCtl) && actions[curCtl] != null && actions[curCtl].Item2 != null)
actions[curCtl].Item2();
curCtl = null;
}
}
Related
I use dragging control by mouse
Problem is if Control.Enabled = false. Dragging can't work? Is there any method to overload to prevent this behavior?
static void control_MouseEnter(object sender, EventArgs e)
{
(sender as Control).Enabled = false;
(sender as Control).Cursor = Cursors.SizeAll;
}
static void control_MouseLeave(object sender, EventArgs e)
{
(sender as Control).Enabled = true;
// (sender as Control).Cursor = Cursors.Default;
}
static void control_MouseDown(object sender, MouseEventArgs e)
{
mouseLocation = e.Location;
// turning on dragging
draggables[(Control)sender] = true;
}
static void control_MouseUp(object sender, MouseEventArgs e)
{
// turning off dragging
draggables[(Control)sender] = false;
}
static void control_MouseMove(object sender, MouseEventArgs e)
{
// only if dragging is turned on
if (draggables[(Control)sender] == true)
{
var control = (sender as Control);
control.Left = e.X + control.Left - mouseLocation.X;
control.Top = e.Y + control.Top - mouseLocation.Y;
}
}
You could use IMessageFilter to trap WM_MOUSEMOVE.
Here I'm changing the caption of the form when the mouse is moved within pictureBox1. It also tells you whether the left mouse button is down:
public partial class Form1 : Form
{
private MyFilter mf;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
pictureBox1.Enabled = false;
mf = new MyFilter();
mf.PreFilterMouseMove += Mf_PreFilterMouseMove;
Application.AddMessageFilter(mf);
}
private void Mf_PreFilterMouseMove()
{
Point pt = pictureBox1.PointToClient(Cursor.Position);
if (pictureBox1.ClientRectangle.Contains(pt))
{
bool leftDown = (Control.MouseButtons == MouseButtons.Left);
this.Text = "leftDown = " + leftDown + " : position = " + pt.ToString();
}
else
{
this.Text = "...not within pictureBox1...";
}
}
}
public class MyFilter : IMessageFilter
{
private const int WM_MOUSEMOVE = 0x200;
public delegate void dlgMouseMove();
public event dlgMouseMove PreFilterMouseMove;
public bool PreFilterMessage(ref Message m)
{
switch (m.Msg)
{
case WM_MOUSEMOVE:
if (PreFilterMouseMove != null)
{
PreFilterMouseMove();
}
break;
}
return false;
}
}
I appear to have all of the things necessary for Drag-n-Drop to be working, yet my code is not called when I attempt to drag something from one control to another.
I created a Test Class to use to create data:
class TestClass
{
public TestClass()
{
Name = "Blank";
Id = -1;
}
public String Name { get; set; }
public int Id { get; set; }
public object Data { get; set; }
public override String ToString()
{
return String.Format("{0}: {1}", Id, Name);
}
}
I created an empty form with 2 List View controls, listView1 and listView2:
I created event handlers for all of the Drag-n-Drop methods and put breakpoints on them:
private void Form_DragDrop(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Copy;
if (e.Data.GetDataPresent(typeof(TestClass)))
{
var item = e.Data.GetData(typeof(TestClass)) as TestClass;
if (item != null)
{
// ?
}
}
}
private void Form_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Copy;
if (sender.Equals(listView2))
{
e.Effect = DragDropEffects.All;
if (e.Data != null)
{
var format = GetString(e);
Console.WriteLine("{0} has a(n) {1} entering it.", listView2.Name, format);
}
}
}
private void Form_DragLeave(object sender, EventArgs e)
{
if (sender.Equals(listView2))
{
}
}
private void Form_DragOver(object sender, DragEventArgs e)
{
// Code Project Article 9017 says DragOver fires repeatedly, even if the mouse does not move.
if ((e.X != _lastX) || (e.Y != _lastY))
{
_lastX = e.X;
_lastY = e.Y;
if (e.Data.GetDataPresent(typeof(TestClass)))
{
}
else
{
e.Effect = DragDropEffects.None;
}
}
}
private void Form_GiveFeedback(Object sender, GiveFeedbackEventArgs e)
{
if (sender.Equals(listView2))
{
// ?
}
}
private void Form_QueryContinueDrag(object sender, QueryContinueDragEventArgs e)
{
var listView = sender as ListView;
if (listView != null)
{
}
}
private String GetString(DragEventArgs e)
{
var result = String.Empty;
if ((e.AllowedEffect & DragDropEffects.Copy) == DragDropEffects.Copy)
{
var formats = e.Data.GetFormats();
foreach (var format in formats)
{
Console.WriteLine("Data is in the format of [{0}].", format);
result = format;
}
}
return result;
}
I wired both controls up after the constructor's InitializeComponent();:
public ListViewsForm()
{
InitializeComponent();
// Setup ListView 1:
listView1.AllowDrop = true;
listView1.DragDrop += Form_DragDrop;
listView1.DragEnter += Form_DragEnter;
listView1.DragLeave += Form_DragLeave;
listView1.DragOver += Form_DragOver;
listView1.GiveFeedback += Form_GiveFeedback;
listView1.QueryContinueDrag += Form_QueryContinueDrag;
listView1.Dock = DockStyle.Fill;
listView1.View = View.List;
// Setup ListView 2:
listView2.AllowDrop = true;
listView2.DragDrop += Form_DragDrop;
listView2.DragEnter += Form_DragEnter;
listView2.DragLeave += Form_DragLeave;
listView2.DragOver += Form_DragOver;
listView2.GiveFeedback += Form_GiveFeedback;
listView2.QueryContinueDrag += Form_QueryContinueDrag;
listView2.Dock = DockStyle.Fill;
// Create some data:
var group1 = new ListViewGroup("Known Colors");
foreach (KnownColor known in Enum.GetValues(typeof(KnownColor)))
{
var item = new TestClass()
{
Name = known.ToString(),
Id = (int)known,
Data = known,
};
var color = Color.FromKnownColor(known);
var lvi = new ListViewItem(item.ToString(), group1) {
BackColor = Color.FromArgb(color.ToArgb() ^ 0xffffff),
ForeColor = color,
Tag = item,
};
listView1.Items.Add(lvi);
}
}
Whenever I run the project, everything loads up fine, but any attempt to drag an item from the LEFT side to the RIGHT side does nothing. None of my break points are hit. Nothing happens.
What have I left out?
You are missing a handy event and the method that starts the dragging operation:
listView1.ItemDrag += listView1_ItemDrag;
void listView1_ItemDrag(object sender, ItemDragEventArgs e) {
DoDragDrop(e.Item, DragDropEffects.Copy);
}
I have a dll which adds/removes Canvases, and deals with drawing on them.
I wish to "register" each Canvas I add to MouseMove, MouseDown and MouseUp events.
I know I can add those 3 event functions and do it the traditional way, but I wanted to know if there is a more elegant way of doing that in MVVM?
I tried to search for it, but found only implementation of it in the xaml using Interactivity.
There are a couple of ways of doing this but in my experience you'll save yourself a lot of work by creating a Blend behavior. Start by declaring an interface you can use to communicate with your view model, here's a very simple one:
public interface IMouseCaptureProxy
{
event EventHandler Capture;
event EventHandler Release;
void OnMouseDown(object sender, MouseCaptureArgs e);
void OnMouseMove(object sender, MouseCaptureArgs e);
void OnMouseUp(object sender, MouseCaptureArgs e);
}
public class MouseCaptureArgs
{
public double X {get; set;}
public double Y { get; set; }
public bool LeftButton { get; set; }
public bool RightButton { get; set; }
}
Then the behavior itself:
public class MouseCaptureBehavior : Behavior<FrameworkElement>
{
public static readonly DependencyProperty ProxyProperty = DependencyProperty.RegisterAttached(
"Proxy",
typeof(IMouseCaptureProxy),
typeof(MouseCaptureBehavior),
new PropertyMetadata(null, OnProxyChanged));
public static void SetProxy(DependencyObject source, IMouseCaptureProxy value)
{
source.SetValue(ProxyProperty, value);
}
public static IMouseCaptureProxy GetProxy(DependencyObject source)
{
return (IMouseCaptureProxy)source.GetValue(ProxyProperty);
}
private static void OnProxyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.OldValue is IMouseCaptureProxy)
{
(e.OldValue as IMouseCaptureProxy).Capture -= OnCapture;
(e.OldValue as IMouseCaptureProxy).Release -= OnRelease;
}
if (e.NewValue is IMouseCaptureProxy)
{
(e.NewValue as IMouseCaptureProxy).Capture += OnCapture;
(e.NewValue as IMouseCaptureProxy).Release += OnRelease;
}
}
static void OnCapture(object sender, EventArgs e)
{
var behavior = sender as MouseCaptureBehavior;
if (behavior != null)
behavior.AssociatedObject.CaptureMouse();
}
static void OnRelease(object sender, EventArgs e)
{
var behavior = sender as MouseCaptureBehavior;
if (behavior != null)
behavior.AssociatedObject.ReleaseMouseCapture();
}
protected override void OnAttached()
{
base.OnAttached();
this.AssociatedObject.PreviewMouseDown += OnMouseDown;
this.AssociatedObject.PreviewMouseMove += OnMouseMove;
this.AssociatedObject.PreviewMouseUp += OnMouseUp;
}
protected override void OnDetaching()
{
base.OnDetaching();
this.AssociatedObject.PreviewMouseDown -= OnMouseDown;
this.AssociatedObject.PreviewMouseMove -= OnMouseMove;
this.AssociatedObject.PreviewMouseUp -= OnMouseUp;
}
private void OnMouseDown(object sender, MouseButtonEventArgs e)
{
var proxy = GetProxy(this);
if (proxy != null)
{
var pos = e.GetPosition(this.AssociatedObject);
var args = new MouseCaptureArgs {
X = pos.X,
Y = pos.Y,
LeftButton = (e.LeftButton == MouseButtonState.Pressed),
RightButton = (e.RightButton == MouseButtonState.Pressed)
};
proxy.OnMouseDown(this, args);
}
}
private void OnMouseMove(object sender, MouseEventArgs e)
{
var proxy = GetProxy(this);
if (proxy != null)
{
var pos = e.GetPosition(this.AssociatedObject);
var args = new MouseCaptureArgs {
X = pos.X,
Y = pos.Y,
LeftButton = (e.LeftButton == MouseButtonState.Pressed),
RightButton = (e.RightButton == MouseButtonState.Pressed)
};
proxy.OnMouseMove(this, args);
}
}
private void OnMouseUp(object sender, MouseButtonEventArgs e)
{
var proxy = GetProxy(this);
if (proxy != null)
{
var pos = e.GetPosition(this.AssociatedObject);
var args = new MouseCaptureArgs
{
X = pos.X,
Y = pos.Y,
LeftButton = (e.LeftButton == MouseButtonState.Pressed),
RightButton = (e.RightButton == MouseButtonState.Pressed)
};
proxy.OnMouseUp(this, args);
}
}
}
Then you just add it to whichever control you want mouse event notification on:
<Canvas>
<i:Interaction.Behaviors>
<behaviors:MouseCaptureBehavior Proxy="{Binding}" />
</i:Interaction.Behaviors>
In this case I'm binding Proxy to the DataContext, which happens to be a MainViewModel, so make sure MainViewModel inherits IMouseCaptureProxy. Then it's a simple matter of implementing the various handlers and the Capture/Release handlers which you can then raise to capture and release the mouse, should you need to:
public event EventHandler Capture;
public event EventHandler Release;
public void OnMouseDownobject sender, MouseCaptureArgs e)
{
this.Capture(sender, null);
// etc
}
Some would argue that passing sender into the handlers is technically a violation of MVVM, and personally I'd say I probably agree with this, but this should at least be enough to get you started. If you're an MVVM purist then you'll want to modify the behaviour to instead create intermediate objects that track that kind of thing internally.
I got a Stackpanel containing many buttons, so how can I reorder my buttons by draging & droping them like Expression Blend or "Visual Studio Xaml Window Designer" does
This thread provides some useful information. Nevertheless, there are a lot of resources that you can find in by searching which would provide a lot of information on this.
I am developing an arrangeable stack panel, when I touch or press the item and release the mouse and move the object or child in the stack panel is stick with it. my Code is as below.
namespace Controls.ArrangableGrid
{
using System;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using System.ComponentModel;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Documents;
public class ArrangableControl : StackPanel
{
#region - Variables -
private bool _isDown;
private bool _isDragging;
private Point _startPoint;
private DragAdorner _adorner;
private UIElement _draggedItem = null;
private int _draggedItemIndex = -1;
private ILoggingService _logging = null;
private ILogger _logger;
private CypherComponentModel _parentComponent = null;
#endregion
public ArrangableControl()
{
Orientation = Orientation.Horizontal;
Background = Brushes.Transparent;
if (!DesignerProperties.GetIsInDesignMode(this))
{
Loaded += OnLoaded;
}
}
#region - Functions -
private void SetEvetns()
{
AllowDrop = true;
Drop += OnDrop;
StylusDown += OnEventDown;
StylusUp += OnEventUp;
StylusMove += OnEventMove;
MouseLeftButtonDown += OnEventDown;
MouseLeftButtonUp += OnEventUp;
MouseMove += OnEventMove;
}
private Point GetPosition(InputEventArgs e, IInputElement obj)
{
if (e is MouseEventArgs)
{
Mouse.Capture(obj);
return (e as MouseEventArgs).GetPosition(obj);
}
else if (e is TouchEventArgs)
{
(e as TouchEventArgs).TouchDevice.Capture(obj);
return (e as TouchEventArgs).GetTouchPoint(obj).Position;
}
else if (e is StylusEventArgs)
{
Stylus.Capture(obj);
return (e as StylusEventArgs).GetPosition(obj);
}
return new Point();
}
private void DragStarted()
{
if (_draggedItem == null) return;
_isDragging = true;
_adorner = new DragAdorner(_draggedItem);
var layer = AdornerLayer.GetAdornerLayer(_draggedItem);
layer.Add(_adorner);
}
private void DragMoved()
{
var currentPosition = Mouse.GetPosition(this);
_adorner.LeftOffset = currentPosition.X - _startPoint.X;
_adorner.TopOffset = currentPosition.Y - _startPoint.Y;
}
private void DragFinished(bool cancelled, InputEventArgs e)
{
this.ReleaseMouseCapture();
if (null != _adorner)
AdornerLayer.GetAdornerLayer(_adorner.AdornedElement).Remove(_adorner);
if (cancelled == false)
{
UIElement _dropItem = this.GetChildElement(GetPosition(e, this)) as UIElement;
if (null != _dropItem)
DragDrop.DoDragDrop(_draggedItem, new DataObject("UIElement", e.Source, true), DragDropEffects.Move);
}
_adorner = null;
_isDragging = false;
_isDown = false;
}
#endregion
#region - Events -
private void OnLoaded(object sender, RoutedEventArgs e)
{
if (this.IsLoaded)
{
SetEvetns();
}
}
private void OnEventDown(object sender, InputEventArgs e)
{
if(e.Source != this)
{
_isDown = true;
_isDragging = false;
_startPoint = GetPosition(e, this);
_draggedItem = e.Source as UIElement;
if (null != _draggedItem)
_draggedItemIndex = this.Children.IndexOf(_draggedItem);
}
}
private void OnEventUp(object sender, InputEventArgs e)
{
if (_isDown && _isDragging)
{
DragFinished(false, e);
e.Handled = true;
}
else
{
e.Handled = true;
ReleaseMouseCapture();
ReleaseAllTouchCaptures();
ReleaseStylusCapture();
}
}
private void OnEventMove(object sender, InputEventArgs e)
{
if (_isDown)
{
if ((_isDragging == false) &&
((Math.Abs(GetPosition(e, this).X - _startPoint.X) > SystemParameters.MinimumHorizontalDragDistance) ||
(Math.Abs(GetPosition(e, this).Y - _startPoint.Y) > SystemParameters.MinimumVerticalDragDistance)))
DragStarted();
if (_isDragging)
DragMoved();
}
e.Handled = true;
}
private void OnDrop(object sender, DragEventArgs e)
{
try
{
UIElement droptarget = e.Source as UIElement;
int droptargetIndex = this.Children.IndexOf(droptarget);
if (_draggedItem != null && (droptargetIndex != _draggedItemIndex))
{
if (droptargetIndex != -1)
{
this.Children.Remove(_draggedItem);
this.Children.Insert(droptargetIndex, _draggedItem);
}
}
_draggedItem = null;
_draggedItemIndex = -1;
}
catch (Exception ex)
{
_logger.Error($"Drop Error: {ex} at {nameof(ArrangableControl)}");
}
finally
{
e.Handled = true;
ReleaseMouseCapture();
ReleaseAllTouchCaptures();
ReleaseStylusCapture();
}
}
#endregion
}
}
I created simple UserControl with several labels. How can I implement simple mechanism, that allows moving whole control like normal window (when I add it to winForms - if it makes difference)
You can use my Capture class:
public class ClsCapture
{
bool bCaptureMe;
Point pLocation = new Point();
Control dd;
//Handles dad.MouseDown, dd.MouseDown
private void Form1_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
try {
bCaptureMe = true;
pLocation = e.GetPosition(sender);
} catch {
}
}
//Handles dad.MouseMove, dd.MouseMove
private void Form1_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
try {
if (bCaptureMe) {
dd.Margin = new Thickness(dd.Margin.Left - pLocation.X + e.GetPosition(sender).X, dd.Margin.Top - pLocation.Y + e.GetPosition(sender).Y, dd.Margin.Right, dd.Margin.Bottom);
}
} catch {
}
}
//Handles dad.MouseUp, dd.MouseUp
private void Form1_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
try {
bCaptureMe = false;
} catch {
}
}
public ClsCapture(Control pnl)
{
dd = pnl;
dd.PreviewMouseLeftButtonDown += Form1_MouseDown;
dd.PreviewMouseLeftButtonUp += Form1_MouseUp;
dd.PreviewMouseMove += Form1_MouseMove;
}
public static void CaptureMe(Control pnl)
{
ClsCapture cc = new ClsCapture(pnl);
}
}
Usage:
ClsCapture.CaptureMe(AnyControlYouWant);