Having minimum mousedown time on control - c#

I have a control (basically an ON/OFF toggle switch) which I want the user to press for at least one second before switching states. I can measure the time between the mouse down and mouse up events on the control and make sure the mouse never leaves the control while down, but wanted to know:
Is there was a better method of establishing that the "click" on that control satisfies a minimum time?

There is no simpler way, you must do the steps you have described.
But, this "behavior" can be implemented in a general way - so it can be reused multiple times.
Here is an example of such implementation:
public class LongClick
{
public static void Attach(Control Control, EventHandler Handler)
{
var LC = new LongClick { Control = Control, Handler = Handler };
Control.MouseDown += LC.ControlOnMouseDown;
Control.MouseMove += LC.ControlOnMouseMove;
Control.MouseUp += LC.ControlOnMouseUp;
}
private Control Control;
public EventHandler Handler;
private DateTime? MDS;
private void ControlOnMouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left) MDS = DateTime.Now;
}
private void ControlOnMouseMove(object sender, MouseEventArgs e)
{
if (MDS == null) return;
if (e.X < 0) MDS = null;
if (e.X > Control.Width) MDS = null;
if (e.Y < 0) MDS = null;
if (e.Y > Control.Height) MDS = null;
}
private void ControlOnMouseUp(object sender, MouseEventArgs e)
{
if (MDS == null) return;
if (e.Button != MouseButtons.Left) return;
var TimePassed = DateTime.Now.Subtract(MDS.Value);
MDS = null;
if (TimePassed.TotalSeconds < 1) return;
if (Handler == null) return;
Handler(Control, EventArgs.Empty);
}
}
And the usage is:
private void Form1_Load(object sender, EventArgs e)
{
LongClick.Attach(button1, button1_LongClick);
}
private void button1_LongClick(object sender, EventArgs e)
{
MessageBox.Show("button1 long clicked!");
}
There are other variations of the implementation, one of them would be to override the control class (it is even simpler than this one).

Related

How to regain focus in application after drag and drop to grid

In my application, I have a form with two panels. Inside one panel is a button. Inside the other is a DevExpress Grid control. The grid is made up of 3 columns. You can drag values from one column into the other to copy it.
My problem is that whenever I do a drag-and-drop from one column to another, the focus on the application goes into an unusual state. The grid remains focused; I can mouse over the headers and see them react as normal. However the rest of the application is not focused. Mouse over the button in the other panel does not react, nor do the menus or form controls. If I click on the button, it reacts like I clicked on an unfocused application. I have to click again to actually activate the button. Same for every control except the grid.
I have tried using Activate() and Focus() on the button and form but to no avail.
namespace Company.StuffUploader
{
public partial class ComputationGrid : DevExpress.XtraEditors.XtraUserControl
{
private BindingList<ComputationLinkModel> _links = new BindingList<ComputationLinkModel>();
public List<ComputationLinkModel> ComputationLinkModels
{
get
{
return new List<ComputationLinkModel>(_links);
}
}
public ComputationGrid()
{
InitializeComponent();
}
private void ComputationGrid_Load(object sender, EventArgs e)
{
_gridControl.DataSource = _links;
}
private DragDropEffects GetDragEffect(DragEventArgs e)
{
var text = e.Data.GetData("System.String") as string;
if (text == null)
return DragDropEffects.None;
var link = GetLinkFromScreenPoint(new Point(e.X, e.Y));
if (link == null)
return DragDropEffects.None;
var tokens = text.Split('\t');
if (tokens.Count() != 2)
return DragDropEffects.None;
var dateString = link.movedate.ToString("yyyy-MM-dd");
if (link.StuffSurfaceName == tokens[0] && dateString != tokens[1])
return DragDropEffects.Move;
else
return DragDropEffects.None;
}
private ComputationLinkModel GetLinkFromScreenPoint(Point screenPt)
{
var pt = _gridControl.PointToClient(screenPt);
var hitInfo = _gridView.CalcHitInfo(pt);
return _gridView.GetRow(hitInfo.RowHandle) as ComputationLinkModel;
}
private void _gridControl_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
var hitInfo = _gridView.CalcHitInfo(e.Location);
if (hitInfo == null || !hitInfo.InRowCell)
return;
// Only allow dragging from target column
if (hitInfo.Column.AbsoluteIndex != 0)
return;
var link = _gridView.GetRow(hitInfo.RowHandle) as ComputationLinkModel;
if (link == null)
return;
var item = string.Format("{0}\t{1}", link.StuffSurfaceName, link.movedate.ToString("yyyy-MM-dd"));
DoDragDrop(item, DragDropEffects.Move);
}
}
private void _gridControl_DragOver(object sender, DragEventArgs e)
{
e.Effect = GetDragEffect(e);
}
private void _gridControl_DragDrop(object sender, DragEventArgs e)
{
}
private void _gridControl_DragEnter(object sender, DragEventArgs e)
{
e.Effect = GetDragEffect(e);
}
private void _unlinkButton_Click(object sender, EventArgs e)
{
}
}
}
I figured out my own problem. Calling DoDragDrop() from within MouseDown event does not seem to work correctly. The proper way is to call it from MouseMove(). The documentation on MSDN hints at this in its example code.
Ensure that you set the DXMouseEventArgs.Handled property to true in the GridView's Mouse~ event handlers. It guarantees that default handling of these events will be prohibited. Review this example to see how to do this.

C# WPF Drag and Drop Button within StackPanel on a Canvas

This may be a basic question but I just started using WPF and I am having troubles trying to do a simple drag and drop.
I created this ToolboxButton class:
public class ToolboxButton : Button
{
private bool _isDragging = false;
private Point _startPoint;
public ToolboxButton(string content)
{
Content = content;
HorizontalAlignment = HorizontalAlignment.Stretch;
Height = 30;
Loaded += ToolboxButton_Loaded;
}
void ToolboxButton_Loaded(object sender, RoutedEventArgs e)
{
PreviewMouseLeftButtonDown += ToolboxButton_PreviewMouseLeftButtonDown;
PreviewMouseMove += ToolboxButton_PreviewMouseMove;
}
void ToolboxButton_PreviewMouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed && !_isDragging)
{
Point position = e.GetPosition(null);
if (Math.Abs(position.X - _startPoint.X) > SystemParameters.MinimumHorizontalDragDistance ||
Math.Abs(position.Y - _startPoint.Y) > SystemParameters.MinimumVerticalDragDistance)
{
StartDrag(e);
}
}
}
void ToolboxButton_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
_startPoint = e.GetPosition(null);
}
private void StartDrag(MouseEventArgs e)
{
_isDragging = true;
DataObject data = new DataObject(System.Windows.DataFormats.Text.ToString(), "abcd");
DragDrop.DoDragDrop(e.Source as ToolboxButton, data, DragDropEffects.Move);
_isDragging = false;
}
}
This button is added in a stackpanel like so:
ToolboxButton btnAddButton = new ToolboxButton("Button");
_toolboxView.Children.Add(btnAddButton); // _toolboxView is a stackpanel
And I have a Canvas with the following code:
public class DesignerView : Canvas
{
public DesignerView()
{
AllowDrop = true;
DragOver += DesignerView_DragOver;
Drop += DesignerView_Drop;
PreviewDragOver += DesignerView_PreviewDragOver;
}
void DesignerView_PreviewDragOver(object sender, DragEventArgs e)
{
MessageBox.Show("previewdragover");
}
void DesignerView_DragOver(object sender, DragEventArgs e)
{
MessageBox.Show("dragover");
if (!e.Data.GetDataPresent(typeof(ToolboxButton)))
{
e.Effects = DragDropEffects.None;
e.Handled = true;
}
}
void DesignerView_Drop(object sender, DragEventArgs e)
{
MessageBox.Show("drop");
if (e.Data.GetDataPresent(typeof(ToolboxButton)))
{
ToolboxButton droppedThingie = e.Data.GetData(typeof(ToolboxButton)) as ToolboxButton;
MessageBox.Show("You dropped: " + droppedThingie.Content);
}
}
public UIElement GetView()
{
return this;
}
}
Both Canvas and StackPanel are added in the main window like so:
Grid contentGrid = new Grid();
Content = contentGrid;
contentGrid.Children.Add(_toolboxView.GetView());
contentGrid.Children.Add(_designerView.GetView());
None of the MessageBoxes ever fire and I can't find out why. The cursor changes to the "Cannot pin", a dark circle with a diagonal line inside.
Am I missing something ? I want everything to be done in the code without XML.
Maybe I have to do something on the StackPanel but I tried the code of ToolboxButton there and it didn't work either.
As I can see you done all job, just DesignerView_drop left to correct.
use sender object to grab dragged object (in this example button)
void DesignerView_Drop(object sender, DragEventArgs e)
{
MessageBox.Show("drop");
Button btn = (Button)sender;
contentGrid.Children.Add(btn);
}

Why are Stylus and Mouse events fired when touching my object?

I have a PushPin object I have hooked up to a handful of Touch / Stylus / Mouse events:
pp.MouseDown += pp_MouseDown;
pp.TouchDown += pp_TouchDown;
pp.TouchUp += pp_TouchUp;
pp.StylusDown += pp_StylusDown;
pp.StylusUp += pp_StylusUp;
Handlers
void pp_MouseDown(object sender, MouseButtonEventArgs e)
{
PushPinUpOrDown(sender);
e.Handled = true;
}
private void pp_TouchDown(object sender, TouchEventArgs e)
{
var pushpin = (sender as Pushpin);
pushpin.CaptureTouch(e.TouchDevice);
e.Handled = true;
}
void pp_StylusDown(object sender, StylusDownEventArgs e)
{
var pushpin = (sender as Pushpin);
pushpin.CaptureStylus();
e.Handled = true;
}
void pp_StylusUp(object sender, StylusEventArgs e)
{
var pushpin = (sender as Pushpin);
e.Handled = true;
if (pushpin != null && e.StylusDevice.Captured == pushpin)
{
PushPinUpOrDown(sender);
pushpin.ReleaseStylusCapture();
}
}
void pp_TouchUp(object sender, TouchEventArgs e)
{
var pushpin = (sender as Pushpin);
e.Handled = true;
if (pushpin != null && e.TouchDevice.Captured == pushpin)
{
PushPinUpOrDown(sender);
pushpin.ReleaseTouchCapture(e.TouchDevice);
}
}
but when I touch my PushPin firstly the StylusDown event fires then followed by the MouseDown. The TouchDown event I would expect to fire never fires.
Why is this? is this a problem with my program or my monitor?
Do I need both Stylus and Touch events?
(I am using a touch enabled monitor not tablet or anything)
So from here I got the code:
void pp_StylusDown(Object sender, StylusEventArgs e)
{
if (sender != null)
{
//Capture the touch device (i.e. finger on the screen)
e.StylusDevice.Capture(sender as Pushpin);
}
}
void pp_StylusUp(Object sender, StylusEventArgs e)
{
var device = e.StylusDevice;
if (sender != null && device.Captured == sender as Pushpin)
{
(sender as Pushpin).ReleaseStylusCapture();
PushPinUpOrDown(sender, true);
e.Handled = true;
}
}
which stopped the MouseDown event firing. The main reason (strangely) was removing e.Handled = true from pp_StylusDown fixed the problem
Still doesn't explain why the stylus event fires when touching the screen

Making a panel draggable

I am creating a "cropping tool", and i need to make a panel that contains 2 buttons draggable.
Until now i've tried something like this, but the change location event happens only when i click the right button of the mouse...
this.MouseDown += new MouseEventHandler(onRightClickMouse);
private void onRightClickMouse(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
Point localMouseClickPoint = new Point(e.X, e.Y);
panel1.Location = localMouseClickPoint;
}
}
My question: How can i make that panel draggable in my form?(I mean click on the panel then drag it to a location).
Try something like this:
delegate void updatePanelCallback();
panel1.MouseDown += new MouseEventHandler(onMouseDown);
panel1.MouseUp += new MouseEventHandler(onMouseUp);
System.Timers.Timer runTimer = new System.Timers.Timer(100);
runTimer.Elapsed += new ElapsedEventHandler(onTimerElapsed);
private void onMouseDown(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Right)
{
return;
}
runTimer.Enabled = false;
}
private void onMouseUp(object sender, MouseEventArgs e)
{
runTimer.Enabled = false;
}
public void updatePanelLocation()
{
if (this.InvokeRequired)
{
this.Invoke(new updatePanelCallback(updatePanelLocation), new object[] {});
}
else
{
Cursor curs = new Cursor(Cursor.Current.Handle);
panel1.Location = curs.Position;
}
}
private void onTimerElapsed(object source, ElapsedEventArgs e)
{
updatePanelLocation();
}
You could try something in two steps, preparing the action on MouseDown event and finishing it on MouseUp.

Get Mouse State without access to MouseEventArgs?

I have a form with many, many controls. I need to detect if the mouse is down or if it's up. Most of the time, I don't have MouseEventArgs.
Is there a quick and easy way to tell if the mouse is down without mouseEventArgs?
Is there an alternative, or is something like this the only way?:
foreach (Control c in this.Controls)
{
c.MouseUp += new MouseEventHandler(globalMouseUp);
c.MouseDown += new MouseEventHandler(globalMouseDown);
}
bool isMouseUp = true;
private void globalMouseDown(object sender, MouseEventArgs e)
{
isMouseUp = false;
}
private void globalMouseUp(object sender, MouseEventArgs e)
{
isMouseUp = true;
}
You can try checking with a timer:
private void timer1_Tick(object sender, EventArgs e) {
this.Text = "Mouse Is " + (Control.MouseButtons == MouseButtons.Left);
}
ChecK Control.MouseButtons static property:
if (Control.MouseButtons == MouseButtons.Left)
{
}

Categories