I have to handle both the single click and the double click of a button in a WPF application with different reaction.
Unfortunately, on a doubleclick, WPF fires two click event and a double click event, so it's hard to handle this situation.
It tried to solve it using a timer but without success...I hope you can help me.
Lets see the code:
private void delayedBtnClick(object statInfo)
{
if (doubleClickTimer != null)
doubleClickTimer.Dispose();
doubleClickTimer = null;
this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new VoidDelegate(delegate()
{
// ... DO THE SINGLE CLICK ACTION
}));
}
private void btn_Click(object sender, RoutedEventArgs e)
{
if (doubleClickTimer == null)
doubleClickTimer = new Timer(delayedBtnClick, null, System.Windows.Forms.SystemInformation.DoubleClickTime, Timeout.Infinite);
}
}
}
private void btnNext_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
if (doubleClickTimer != null)
doubleClickTimer.Change(Timeout.Infinite, Timeout.Infinite); // disable it - I've tried it with and without this line
doubleClickTimer.Dispose();
doubleClickTimer = null;
//.... DO THE DOUBLE CLICK ACTION
}
The problem is that the 'SINGLE CLICK ACTION' called after the 'DOUBLE CLICK ACTION' on doubleclick. It's strange that I set thedoubleClickTimer to null on double click but in the delayedBtnClick it's true :O
I've already tried to use longer time, a bool flag and lock...
Do you have any ideas?
Best!
If you set the RoutedEvent's e.Handled to true after handling the MouseDoubleClick event then it will not call the Click Event the second time after the MouseDoubleClick.
There's a recent post which touches on having different behaviors for SingleClick and DoubleClick which may be useful.
However, if you are sure you want separate behaviors and want/need to block the first Click as well as the second Click, you can use the DispatcherTimer like you were.
private static DispatcherTimer myClickWaitTimer =
new DispatcherTimer(
new TimeSpan(0, 0, 0, 1),
DispatcherPriority.Background,
mouseWaitTimer_Tick,
Dispatcher.CurrentDispatcher);
private void Button_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
// Stop the timer from ticking.
myClickWaitTimer.Stop();
Trace.WriteLine("Double Click");
e.Handled = true;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
myClickWaitTimer.Start();
}
private static void mouseWaitTimer_Tick(object sender, EventArgs e)
{
myClickWaitTimer.Stop();
// Handle Single Click Actions
Trace.WriteLine("Single Click");
}
You could try this:
Button.MouseLeftButtonDown += Button_MouseLeftButtonDown;
private void Button_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
if (e.ClickCount > 1)
{
// Do double-click code
}
else
{
// Do single-click code
}
}
If neccessary, you could require mouse click and wait until mouse up to perform the action.
Related
I need to know if there is a way to access to the events of the buttons inside a RepositoryItemTimeSpanEdit.
Image to see the buttons I need the events for: Click
Image
I have tried to access in the PopUp event and QueryPopUp, however I can't get the button in any way yet.
You can get this form through Form.OwnedForms property in Popup event. The type of this form is DevExpress.XtraEditors.Popup.TimeSpanEditDropDownForm, so you need just to find the form of this type. After that you can access buttons by using TimeSpanEditDropDownForm.OkButton property and TimeSpanEditDropDownForm.CloseButton property.
Here is example:
private void repositoryItemTimeSpanEdit1_Popup(object sender, EventArgs e)
{
var popupForm = (TimeSpanEditDropDownForm)OwnedForms.FirstOrDefault(item => item is TimeSpanEditDropDownForm);
if (popupForm == null)
return;
popupForm.OkButton.Click += OkButton_Click;
popupForm.CloseButton.Click += CloseButton_Click;
}
private void OkButton_Click(object sender, EventArgs e)
{
MessageBox.Show("Ok");
}
private void CloseButton_Click(object sender, EventArgs e)
{
MessageBox.Show("Cancel");
}
I write certain code in my form ResizeEnd event. Now problem is when form is moved by clicking and dragging on the caption bar, ResizeEnd event is fired and code is executed even though form size is NOT changed.
I gone through MSDN documentation for Resizeend event and it says that event will fire when form is moved (don't understand why this happens when the size is NOT changed).
For resolution I put the if condition to check if size is changed like below to stop execution of code on form move:
int Prv_Height; int Prv_Width;
private void TemplateGrid_ResizeEnd(object sender, EventArgs e)
{
if (this.Size.Width != Prv_Width || this.Size.Height != Prv_Height)
{
Prv_Width = this.Size.Width;
Prv_Height = this.Size.Height;
//Other code here when form resize ends...
}
}
So is there any way to stop ResizeEnd event to fire when form is moved? or any other better approach to solve the problem?
You could move your check for sizechange to a new baseform. On derived forms the resizeEnd event will then only fire if the size is actually changed.
public partial class CustomForm : Form
{
private Size _prvSize;
public CustomForm()
{
InitializeComponent();
}
protected override void OnShown(EventArgs e)
{
_prvSize = this.Size;
base.OnShown(e);
}
protected override void OnResizeEnd(EventArgs e)
{
if (this.Size == _prvSize)
return;
_prvSize = this.Size;
base.OnResizeEnd(e);
}
}
private void Form1_ResizeBegin(object sender, EventArgs e)
{
oldSize = ClientSize;
}
private Size oldSize = new Size();
private void Form1_ResizeEnd(object sender, EventArgs e)
{
if (oldSize == ClientSize)
return;
//Add Something
}
i have a situation where : User moves mouse over the image .
If user keeps mouse on that image for specific time ex. 2 seconds then only i have to proceed
further in mouseenter event otherwise don't.
I have already refred to http://forums.silverlight.net/t/86671.aspx/1 but looks like mine is different case.
One option is to use a DispatchTimer to determine the length of the mouse over.
bool isMouseOverImage = false;
public void Image_MouseEnter(object sender, MouseEventArgs e)
{
this.isMouseOverImage = true;
var timer = new System.Windows.Threading.DispatcherTimer();
timer.Interval = TimeSpan.FromSeconds(2);
timer.Tick += (object timerSender, EventArgs timerArgs) =>
{
if(this.isMouseOverImage)
{
// write your code
}
// stop the timer
timer.Stop();
};
timer.Start();
}
public void Image_MouseLeave(object sender, MouseEventArgs e)
{
this.isMouseOverImage = false;
}
If you have multiple images, you should create a re-usable Behavior and attach it to each image. I can define code for that if that would help.
I'm having a issue with the following scenario on Windows Forms:
I created a Form with two buttons, each button have been assigned with the behaviour DialogResult OK and DialogResult Cancel, respectively.
But based on certain conditions, I need to stop the execution of the OK button. The problem is that if I just made a return like this:
private void btnOk_Click(object sender, EventArgs e)
{
foreach(Control control in tblTable.Controls)
{
if (control.GetType() == typeof(TextBox))
{
if (control.Text.Trim() == "")
{
control.Focus(); return;
}
}
else
{
}
}
}
The dialog result keeps returning the OK answer to the parent form.
I need to stop the execution of the event and not return any answer until the user corrects the info on the form. In other words, the user should be taken back to the form to correct any missing or wrong data.
As Hans Passant mentions in an comment, just set the DialogResult to None!
Like this:
private void btnOk_Click(object sender, EventArgs e)
{
if(ValidationFailed())
{
this.DialogResult = DialogResult.None;
return;
}
//...
}
Personally I wouldn't use DialogResults on buttons in this scenario. I only tend to set the DialogResult when there's only distinct options that do not require any additional logic (i.e. making a custom MessageBox).
What I would do is to just send the DialogResult yourself on success:
private void btnOk_Click(object sender, EventArgs e)
{
if (allIsOK())
{
this.DialogResult = DialogResult.OK;
}
}
Consider tapping into the Forms's Closing event, and use the Cancel property of the event args to cancel form closing.
Here's a web page that discusses the idea; it's VB, but you'll get the idea:
http://www.vbinfozine.com/t_wfdlg.shtml
In Case you have used DialogResult on a button in a child Form (Which is a dialog), and want to return to form with no dialog result use a function on the form_closing() event:
private void ChildForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (notValidated)
{
e.Cancel = true;
}
}
Assume I have a button and I want the following behavior:
when I click on the button, it fires up an event - ok, that's easy.
Now, if I click and wait, after a few seconds it suppose to fire up another event. e.g. popup a menu...
how to do that?
Are you checking the MouseUp event?
Is what you are saying if the user holds down the mouse button for 2 seconds to display a popup menu?
What I would do is on the MouseDown event create a separate thread waiting for the 2 seconds. If the MouseUp event is triggered before it expires then do nothing, else do the event.
// This event will be used for tracking if the MouseUp has been received
private System.Threading.AutoResetEvent _stopTrigger;
private void OnMouseDown(object sender, MouseButtonEventArgs e)
{
if (this._stopTrigger == null)
{
this._stopTrigger = new System.Threading.AutoResetEvent(false);
}
Action popupProcess = new Action(this.ShowPopupAfterTime);
// Make the Popup process on a separate thread
popupProcess.BeginInvoke(null, null);
}
private void OnMouseUp(object sender, MouseButtonEventArgs e)
{
if (this._stopTrigger != null)
{
// Sends the signal to the ShowPopupAfterTime that it should NOT display the pop up
// IIt will make WaitOne return true and not go into the if statement
this._stopTrigger.Set();
}
}
private void ShowPopupAfterTime()
{
// Will enter the if after 2 seconds
if (!this._stopTrigger.WaitOne(2000))
{
// This means it has NOT be trigged thus I can display the popup
// DISPLAY POPUP
// DON"T FORGET you are on a different thread here, NOT UI thread. You will have to use the Dispatcher to get back
// to the UI thread to display the popup
}
}
Look up Timer() and DispatcherTimer()
I would use threading like this
private void mousedownEvent(object sender, MouseButtonEventArgs e)
{
//Fire off a thread which will do the waiting in the background
new Thread(delegate()
{
//Wait for 2 seconds
Thread.Sleep(2000);
//dump a dowork() method onto the main thread
this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(delegate()
{
doWork(sender);
}));
return;
}).Start();
}
private void doWork(object sender)
{
//if the button is still pressed
if ((sender as UIElement).IsMouseOver && Mouse.LeftButton == MouseButtonState.Pressed)
{
//continue here
}
}
it will check a mouse button is pressed and then check again after 2 seconds without stalling the main app thread. I wou't check if the button was pressed the entire time so this may or may not be important to you
Shane
You can run timer for 2 seconds under MouseDown event and on timers tick event check what you need. Afer that you can stop your timer.
DispatcherTimer PopupTimer = new DispatcherTimer();
PopupTimer.Tick += new EventHandler(PopupTimerTick);
PopupTimer.Interval = new TimeSpan(0, 0, 0, 0,5);
private void PopupTimerTick(object sender, EventArgs e)
{
if (Mouse.LeftButton == MouseButtonState.Pressed)
{
// If still pressed showing popup
((Storyboard)Resources["ShowPopup"]).Begin();
PopupTimer.Stop();
}
}
private void ImageOnMouseDown(object sender, MouseButtonEventArgs e)
{
PopupTimer.Start();
e.Handled = true;
}
private void ImageOnMouseUp(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
if (Popup.IsOpen == false)
{
((Storyboard)Resources["ShowPopup"]).Stop();
// Here the operation that works on the click
}
}