Is this possible to detect a mouse click (Left/Right) anywhere (Inside and Outside the Form) in an if statement? And if it's possible, how?
if(MouseButtons.LeftButton == MouseButtonState.Pressed){
...
}
Here is a starter, if I understood your needs of "clicking from outside the window" and Hans Passant's suggestion doesn't fit your needs. You might need to add an event handler for Form1_Click.
CAUTION: This code is provided to illustrate the concept. The threading synchronization in this sample is not 100% correct. Check the history of this answer for an attempt at a more "threading correct" one that sometimes throws exceptions. As an alternative, to get rid of all threading issues, you could have the task in StartWaitingForClickFromOutside be instead always running (aka be always in "listen" mode) as opposed to trying to detect the "within the form" or "outside the form" states and starting/stopping the loop accordingly.
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.MouseLeave += Form1_MouseLeave;
this.Leave += Form1_Leave;
this.Deactivate += Form1_Deactivate;
this.MouseEnter += Form1_MouseEnter;
this.Activated += Form1_Activated;
this.Enter += Form1_Enter;
this.VisibleChanged += Form1_VisibleChanged;
}
private AutoResetEvent are = new AutoResetEvent(false);
// You could create just one handler, but this is to show what you need to link to
private void Form1_MouseLeave(object sender, EventArgs e) => StartWaitingForClickFromOutside();
private void Form1_Leave(object sender, EventArgs e) => StartWaitingForClickFromOutside();
private void Form1_Deactivate(object sender, EventArgs e) => StartWaitingForClickFromOutside();
private void StartWaitingForClickFromOutside()
{
are.Reset();
var ctx = new SynchronizationContext();
var task = Task.Run(() =>
{
while (true)
{
if (are.WaitOne(1)) break;
if (MouseButtons == MouseButtons.Left)
{
ctx.Send(CLickFromOutside, null);
// You might need to put in a delay here and not break depending on what you want to accomplish
break;
}
}
});
}
private void CLickFromOutside(object state) => MessageBox.Show("Clicked from outside of the window");
private void Form1_MouseEnter(object sender, EventArgs e) => are.Set();
private void Form1_Activated(object sender, EventArgs e) => are.Set();
private void Form1_Enter(object sender, EventArgs e) => are.Set();
private void Form1_VisibleChanged(object sender, EventArgs e)
{
if (Visible) are.Set();
else StartWaitingForClickFromOutside();
}
}
}
If I understood you incorrectly, you might find this useful: Pass click event of child control to the parent control
When user clicks outside the form control, it losses the focus and you can make use of that.which means you have to use the _Deactivate(object sender, EventArgs e) event of the form control to make this work. Since which will trigger when the form loses focus and is no longer the active form. Let Form1 be the form, then the event will be like the following:
private void Form1_Deactivate(object sender, EventArgs e)
{
// Your code here to handle this event
}
One method is to cover the entire screen with a borderless form with the properties set to transparent (a few percent above completely transparent, not sure if total transparency works but you won't notice the difference) and also set to topmost. Then use the events from the form. As soon as a click is detected this will not affect anything underneath the form (which in my application is something I want to happen) but the form could be closed and another mouse click simulated a fraction of a second later to activate the controls that are underneath. I had no problem using the windows API to use mouse hooks in VB6 but cannot seem to find something that works in c# with the 2019 version of .NET so this is a good workaround. Of course to be really clever you could use an irregular forms method to make the transparent form the same shape as the mouse and follow it.
Note: I have just found the complete code to do it using hooks that mere mortals can get up and running at once! KeyboardMouseHooks C# Library - CodePlex Archive
PS if you use my (dumb) method remember to create an escape key or button or you will have to restart your computer unless the form is programmed to disappear for real clicks as suggested!
I know this is late but maybe it helps someone. Using the MouseEventArgs of the MouseUp event of any control you can check for mouse button and wheel among other things. Here is an example.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.MouseUp += Form1_MouseUp;
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
if(e.Button == MouseButtons.Left)
{
DoSomething_LeftClick();
}
else if(e.Button == MouseButtons.Right)
{
DoSomething_RightClick();
}
}
private void DoSomething_LeftClick()
{
//Here some code
}
private void DoSomething_RightClick()
{
//Here some code
}
}
Related
I am looking to simulate a custom tooltip the like of you see in websites using c# .NET 4.5 windows forms.This tooltip will basically show status of some Tasks like how many tasks are pending,tasks in process, completed etc.To do this i am using a borderless win form.This winform will have some texts, images etc.I want it to reveal itself on button's mouseHover event and disappear on MouseLeave event.My problem is that on Mousehover event numerous instances of that tooltip form is getting generated and on MouseLeave they are not getting closed.My code is
private void B_MouseHover(object sender, EventArgs e)
{
frmSecQStatToolTipDlg tooltip = new frmSecQStatToolTipDlg();
tooltip.Location = this.PointToScreen(new Point(this.Left, this.Bottom));
tooltip.Show();
}
private void B_MouseLeave(object sender, EventArgs e)
{
frmSecQStatToolTipDlg tooltip = new frmSecQStatToolTipDlg();
tooltip.Close();
}
My code is not working, hence please tell me how to do this the correct way.Thanks
You're generating a new instance of the form class every time you get a hover event, and every time you get a leave event. If you want to continue to use this approach I would recommend you use a variable on your main form object to store the reference to your tooltip form. Secondly, you need to not generate a new instance whenever the event handler is called, but only when necessary. I would create your instance the first time your Hover event is called for a particular control, and then dispose of it when your Leave handler is called -- this is under the assumption that the tooltip dialog's constructor loads up different information for each control being hovered over. Like so:
frmSecQStatToolTipDlg f_tooltip;
private void B_MouseHover(object sender, EventArgs e)
{
if(frmSecQStatToolTipDlg == null)
{
f_tooltip = new frmSecQStatToolTipDlg();
}
tooltip.Location = this.PointToScreen(new Point(this.Left, this.Bottom));
tooltip.Show();
}
private void B_MouseLeave(object sender, EventArgs e)
{
if(f_tooltip != null)
{
f_tooltip.Close();
f_tooltip = null;
}
}
You should keep a global field for this form, and should not dispose or close it. Just hide it on some events and show again.
Sample Code:
frmSecQStatToolTipDlg tooltip;
private void B_MouseHover(object sender, EventArgs e)
{
if(frmSecQStatToolTipDlg == null)
{
tooltip = new frmSecQStatToolTipDlg();
}
tooltip.Location = this.PointToScreen(new Point(this.Left, this.Bottom));
tooltip.Show();
}
private void B_MouseLeave(object sender, EventArgs e)
{
if(frmSecQStatToolTipDlg != null)
{
tooltip.Hide();
}
}
With this logic you'll not have to create tooltip instance again and again and it will not take time to popup if you frequently do this activity.
Declare your tooltip once as readonly and use it without asking anytime if it is null or not.
If you need to Dispose it, implement the IDisposable pattern:
https://msdn.microsoft.com/en-us/library/b1yfkh5e(v=vs.110).aspx
private readonly frmSecQStatToolTipDlg _tooltip = new frmSecQStatToolTipDlg() ;
private void B_MouseHover(object sender, EventArgs e)
{
_tooltip.Location = this.PointToScreen(new Point(this.Left, this.Bottom));
_tooltip.Show();
}
private void B_MouseLeave(object sender, EventArgs e)
{
_tooltip.Hide();
}
I have multiple custom controls, and I noticed that all of them share the same event (custom) example : OnMoved etc
What I'm doing now is, copy & paste the same code from controls to controls.
So, are there anyway for me to write custom events that can be shared throughout all my controls in C# WPF?
An example of an event that I use for all my controls :
Point lastPosition = new Point();
Point currentPosition = new Point();
public static void OnMoved(object sender, EventArgs e)
{
currentPosition.X = Canvas.GetLeft(explorer);
currentPosition.Y = Canvas.GetTop(explorer);
// didn't moved
if (currentPosition.X == lastPosition.X || currentPosition.Y == lastPosition.Y)
{
return;
}
lastPosition.X = Canvas.GetLeft(explorer);
lastPosition.Y = Canvas.GetTop(explorer);
}
It depends on what exactly you need the event to do, but you could place the event into a shared class:
public class MyEvents
{
public static void SomeEvent(object sender, EventArgs e)
{
MessageBox.Show("hi");
}
}
And then just subscribe to it from wherever you need to:
SomeButton.Click += MyEvents.SomeEvent;
You can create a base class that has a public virtual event, and the event will appear in any classes that derive from the base class. That would keep you from having to copy and paste the same code over and over.
Yes you can! :D The only things you need to have present are:
-> Same Events (The Args of the event have to be exactly the same.
-> They are going to do the same.
The bad thing is that you cannot mix controls with events. For example, you can create a .Click event for a button so it closes your application, but if you wish this to do the same when you press the key "F8" it won't work because the Event arguments are different ~
You can try using a method that makes the same stuff in all your events. Example:
private void _Close()
{
Process.GetCurrentProcess().Close();
}
And you can close with "F5" pressed in the form or with a button click or typyng in a textbox "Close".
button.Click += Button_Close;
private void Button_Close(Object o, RoutedEventArgs e)
{
_Close();
}
this.KeyDown += This_Close;
private void This_Close(Object o, KeyEventArgs e)
{
if(e.KeyCode == Key.F5) _Close();
}
TextBox.TextChanged += Text_Close;
private void Text_Close(Object o, TextChangedEventArgs e)
{
if(TextBox.Text == "Close") _Close();
}
I am hoping someone here can help me, i have a Tabless Control on my windows forms application and basically because the tabs are purposely hidden i have added 2 buttons to each tab "Next" and "Back".
This is the code snippet i have for my "Next" button:
private void nextbutton1_Click(object sender, EventArgs e)
{
tabControl1.SelectedTab = tabPage3;
this.toolStripStatusLabel8.Text = System.DateTime.Now.ToString();
}
Which works fine, however when i use the exact same theory on the "Back" button it does not work:
private void backbutton1_Click(object sender, EventArgs e)
{
tabControl1.SelectedTab = tabmain;
this.toolStripStatusLabel1.Text = System.DateTime.Now.ToString();
}
So my question is how does one go to a previous tabpage from a button? I have looked through here and tried all of the links that came up but nothing has worked any ideas?
You should use the SelectedIndex property instead of using concrete TabPage instances. This way it will still work when you decide to change the order of the pab pages or add new pages:
private void previousButton_Click(object sender, EventArgs e)
{
if (tabControl1.SelectedIndex > 0)
{
tabControl1.SelectedIndex--;
}
}
private void nextButton_Click(object sender, EventArgs e)
{
if (tabControl1.SelectedIndex < tabControl1.TabCount - 1)
{
tabControl1.SelectedIndex++;
}
}
Since there is no "Tabless" tab control in .NET Framework I can only assume that it works similar to the standard TabControl. If the solution doesn't work you should give us some information about the actual class you use.
BTW: There is no need to repeat the buttons on each page. Why don't you just put the buttons outside the TabControl?
Also: I see that you use a ToolStripStatusLabel to show the current time. Instead of updating it each time the user clicks somewhere add a Timer to your form. Set its Interval to 1000 and handle its Tick event. Update the label there:
private void timer1_Tick(object sender, EventArgs e)
{
toolStripStatusLabel1.Text = DateTime.Now.ToLongTimeString();
}
This way it updates constantly and again there is no need to repeat anything. You need to call timer1.Start() in the form's constructor.
I know you will be thinking "Not again this question", as I found like a hundred results when I searched for it. But when I put in the code as described on the pages here, it just minimizes to right above the start menu.
This is the code I use (I added a message box to see if the code gets triggered, but the message box never pops up):
private void Form1_Resize(object sender, EventArgs e)
{
MessageBox.Show("Works1");
if (WindowState == FormWindowState.Minimized)
{
this.Hide();
}
}
Because I don't know if it links to Form1 or Form, I have tried both, to no avail.
private void Form_Resize(object sender, EventArgs e)
{
MessageBox.Show("Works");
if (WindowState == FormWindowState.Minimized)
{
this.Hide();
}
}
Now, when you double click on the Form, it puts this line in the Form1.Designer.cs:
this.Load += new System.EventHandler(this.Form1_Load);
Do I need a similar line to trigger the minimize event?
As you can see, I am completely lost :)
Oh, and it doesn't minimize to the taskbar, as I am using the following code to hide the form on run:
protected override void OnLoad(EventArgs e)
{
Visible = false; // Hide form window.
ShowInTaskbar = false; // Remove from taskbar.
base.OnLoad(e);
}
You need the event
private void Form1_Resize(object sender, EventArgs e)
{
}
Creating Event Handlers on the Windows Forms Designer
Add a NotifyIcon component to your Form. Make sure you set an icon via the properties pane otherwise it will be invisible.
Create an event handler for the form's Control.SizeChanged event. In that event handler place the following code:
sample code:
private void MainForm_SizeChanged(object sender, EventArgs e)
{
if (WindowState == FormWindowState.Minimized)
ShowInTaskbar = false;
}
And then to make the form visible again the NotifyIcon.MouseDoubleClick event handler you can place the following code:
private void trayIcon_MouseDoubleClick(object sender, MouseEventArgs e)
{
WindowState = FormWindowState.Normal;
ShowInTaskbar = true;
}
The basic thing you need to know is events. Events are triggered when certain things happen to your form (or any control). For example, when the form is resized, or loaded, or clicked, an event is raised. You can hook into this event to execute your own code when the event happens.
In your case you want to execute code to minimize the form, on the event that the form is resized. So you need to hook your method to the resize event. The name of your method is not relevant, so let's use a better name:
private void HideWhenMinimized(object sender, EventArgs e)
{
MessageBox.Show("Works1");
if (WindowState == FormWindowState.Minimized)
{
this.Hide();
}
}
To hook your HideWhenMinimized method into the Resize event of the form, you have to do it like this:
this.Resize += new System.EventHandler(this.HideWhenMinimized);
If you add that line of code in the form's constructor or Load event, then your code gets called as soon as the form is resized.
I wish to show the mouse coordinates only when I am viewing tabpage7.
So far I have:
this.tabPage7.MouseMove += new System.Windows.Forms.MouseEventHandler(this.OnMouseMove);
protected void OnMouseMove(object sender, MouseEventArgs mouseEv)
{
Console.WriteLine("happening");
Console.WriteLine(mouseEv.X.ToString());
Console.WriteLine(mouseEv.Y.ToString());
}
but this doesn't appear to be doing anything, could someone help show me what I'm doing wrong please?
Hard to tell what you did wrong, your code is not complete. This works:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
tabPage2.MouseMove += new MouseEventHandler(tabPage2_MouseMove);
}
private void tabPage2_MouseMove(object sender, MouseEventArgs e) {
Console.WriteLine(e.Location.ToString());
}
}
Note that if the tab page contains any controls then those controls will get the mouse move message, not the tab page. Also note that overloading the form's OnMouseMove() method is not a good idea, even though you'll get away with it in this specific case.
Just to be safe...
Where are you subscribing to the MouseMove event? ( where is this.tabPage7.MouseMove += new System.Windows.Forms.MouseEventHandler(this.OnMouseMove); )