I'm newbie of winform. I have opened form2 form a linklabel in form1 using :
private void linkLabel2_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
FrmAddMov frmAddMov = new FrmAddMov();
if(frmAddMov.ShowDialog() == DialogResult.OK)
{
this.Invalidate();
//or
this.Refresh();
}
}
I thought form1 will reload after I submit form2, but not. Please tell me the right way to do it. Thanks a lot, and sorry if my english is too bad.
Gentleman's answer will work, but it can be improved.
When showing a form using ShowDialogthan it is best practice to dispose of that form, and the easiest way to do that is by the using statement
private void linkLabel2_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
using (FrmAddMov frmAddMov = new FrmAddMov())
{
if (frmAddMov.ShowDialog() == DialogResult.OK)
{
FormLoad();
}
}
}
This way you are always 100% sure that all resources for frmAddMov will be cleaned up.
Move everything in your form load event to a method say FormLoad. You may want to add few other statements which you are expecting form reload will do for you. Call this method when your 2nd form closes.
Something like this
private void linkLabel2_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
FrmAddMov frmAddMov = new FrmAddMov();
if(frmAddMov.ShowDialog() == DialogResult.OK)
{
FormLoad();
}
}
Related
In a c# I have two forms: Windows Form1 & Windows Form2.
When I click on a link label in Form1, the second form is shown. But when I close the second form, my first Windows form closes too.
my main form is:
namespace Windows_Forms_Basics
{
public partial class ShowLocationOnMapForm : Form
{
private string latitude;
private string longitute;
private GeoCoordinateWatcher watcher = new GeoCoordinateWatcher();
public ShowLocationOnMapForm()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
watcher = new GeoCoordinateWatcher();
// Catch the StatusChanged event.
watcher.StatusChanged += Watcher_StatusChanged;
// Start the watcher.
watcher.Start();
}
private void button_ShowOnMap_Click(object sender, EventArgs e)
{
textBox_Latitude.Text = latitude;
textBox_Longtitude.Text = longitute;
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "<Pending>")]
private void Watcher_StatusChanged(object sender, GeoPositionStatusChangedEventArgs e) // Find GeoLocation of Device
{
try
{
if (e.Status == GeoPositionStatus.Ready)
{
// Display the latitude and longitude.
if (watcher.Position.Location.IsUnknown)
{
latitude = "0";
longitute = "0";
}
else
{
latitude = watcher.Position.Location.Latitude.ToString();
longitute = watcher.Position.Location.Longitude.ToString();
}
}
else
{
latitude = "0";
longitute = "0";
}
}
catch (Exception)
{
latitude = "0";
longitute = "0";
}
}
private void label1_Click(object sender, EventArgs e)
{
}
private HelpForm form2 = new HelpForm();
private void linkLabel_help_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
this.Hide();
form2.Show();
}
}
}
and my second form is:
namespace Windows_Forms_Basics
{
public partial class HelpForm : Form
{
public HelpForm()
{
InitializeComponent();
}
private void HelpForm_Load(object sender, EventArgs e)
{
}
private void button_BackToForm1_Click(object sender, EventArgs e)
{
ShowLocationOnMapForm form1 = new ShowLocationOnMapForm();
this.Hide();
form1.Show();
}
}
}
Do you have any idea how to tackle this problem?
I am guessing you may be “confusing” forms and one forms “ability” to access another form. Let’s start by taking a look at the bit of code in your initial question…
private HelpForm form2 = new HelpForm();
private void linkLabel_help_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) {
this.Hide();
form2.Show();
}
This code is called from (what appears to be) a Form named ShowLocationOnMapForm.
On this form is a LinkLabel named linkLabel_help and its LinkClicked event is wired up and is shown above.
In addition, there appears to be a “global” variable form2 that is a HelpForm object (first line in the code above), which is another form. It is unnecessary to create this “global” form variable in the ShowLocationOnMapForm. …. However, we will continue as it is not pertinent at this point.
When the user “clicks” the `LinkLabel’ the above method will fire.
On the first Line in the method…
this.Hide();
Is going to “hide” the current form ShowLocationOnMapForm … and “show” the second form (HelpForm) with the line…
form2.Show();
On the surface, this may appear correct, however, there is one problem that I am guessing you are missing. The problem is…
How are you going to “unhide” the first form ShowLocationOnMapForm?
The second form (HelpForm) is “shown”, however, it isn’t going to KNOW anything about the first form. In this situation the first form is basically LOST and you have no way of accessing it. Therefore when you attempt the line… form1.Show(); in the second form, the compiler is going to complain because its not going to know what form1 is. In this code, there is NO way to get back to the first form. It is not only hidden from the user, but from the second form’s perspective the “CODE” can’t see it either!
Your faulty solution is not only “creating” another form1 but it is also doing the same with the second form.
Given this, it appears clear, that if you want to keep access to the first form… then you are going to have to use a ShowDialog instead of Show OR pass the first form to the second form.
Since it is unclear “how” you want these forms to interact, I can only proffer two (2) ways that you can use to at least keep access to the first form.
1) Use ShowDialog instead of Show when displaying the second form. It may look like …
private void linkLabel_help_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) {
HelpForm form2 = new HelpForm();
this.Hide();
form2.ShowDialog();
this.Show();
}
In the code above, the ShowDialog is going to “STOP” code execution in the first form and will wait for the second form (form2) to close. When executed, the first form is hidden, then the second form is shown, however, unlike the Show command, the line this.Show(); will not be executed until the second form closes. I am guessing this may be what you are looking for.
2) Pass the first form to the second form giving the second form “access” to the first form.
This will require that the second form has a “constructor” that takes a ShowLocationOnMapForm object as a parameter. With this, the second form can create a “global” variable of type ShowLocationOnMapForm that “points” to the first form. The constructor may look like…
private ShowLocationOnMapForm parentForm;
public HelpForm(ShowLocationOnMapForm parent) {
InitializeComponent();
parentForm = parent;
}
In the first form, you would instantiate the second form with...
HelpForm form2 = new HelpForm(this);
With this approach, the second form will have total access to the first form. You could add the “back” button as you describe and simply execute the line…ParentForm.Show(); However, I recommend you also wire up the second forms FormClose event and show the first form, otherwise, if the user clicks the close button (top right) and doesn’t click the “back” button, then you will have LOST the first form again.
Without knowing “exactly” how you want these forms to interact it is difficult to proffer a complete solution.
There are also other ways to accomplish this, however these should work for most cases.
I hope this makes sense and helps.
I tried to solve this problem by placing a 'Back to Form1' button in Form2. Which works, and the solution is as follows:
on my Form1 I have:
private Form2 form2 = new HelpForm();
private void linkLabel_help_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
this.Hide();
form2.Show();
}
and on my second form I have:
private void button_BackToForm1_Click(object sender, EventArgs e)
{
HelpForm form1 = new HelpForm();
this.Hide();
form1.Show();
}
But the problem is if I click the close button (on top right of the window) instead of the GoBack button on the second form, Form1 & Form2 both close in the same time.
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
}
}
I need to close a form on a button click event.Here in my example I am hiding the form.Think this is not a good way.When I do only Close() the form is disposed forever and need to rerun the programme to retrieve it.
private void buttonClose_Click(object sender, EventArgs e)
{
this.Close(); //closing frmCalender
}
private void frmCalender_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
this.Hide();
e.Cancel = true;
}
}
Give me the best way to close a C# Windows Form.
If you want to close a form, call .Close().
When I do only Close() the form is disposed forever and need to rerun the programme to retrieve it.
When you close the form, I assume you have no references to it. If so, you can create a new copy of your form via the constructor (var form = new MyForm();).
Otherwise, after closing the form, I believe you should be able to call .Show() on it again, as long as something still has a reference to your form.
I think, the best approach would be:
private void buttonClose_Click(object sender, EventArgs e)
{
this.Hide();
}
I am new to c# and kind of winging it. using Microsoft Visual C# 2010
I have checked many similar posts and none of the suggestions seem to help
I am getting the following error: "Cannot access a disposed object"
which references the main form here
private void btn_RunPkgs_Click(object sender, EventArgs e)
{
RunPackages rp = new RunPackages();
this.Hide();
rp.ShowDialog();//The error points to this line
this.Show();
}
here is the code that blows up when the security check fails.
private void securityCheck()
{
if (MyGlobals.FormCheck("RUN_JOBS") == 1)
{
InitializeComponent();
}
else
{
//this.BeginInvoke(new MethodInvoker(this.Close));
//this.DialogResult = System.Windows.Forms.DialogResult.Cancel;
MessageBox.Show("You do not have permission to access this form!");
//this.Close();
this.Dispose();
}
}
EDIT
It looks like I am going to go with Adriano Repetti's idea of putting the security where I call the page, but I am a little nervous now having any security on the page.
private void btn_RunPkgs_Click(object sender, EventArgs e)
{
if (MyGlobals.FormCheck("RUN_JOBS") == 1)
{
RunPackages rp = new RunPackages();
this.Hide();
rp.ShowDialog();
this.Show();
}
else
{
MessageBox.Show("Not for You!");
}
}
private void btn_ListUpdater_Click(object sender, EventArgs e)
{
if (MyGlobals.FormCheck("MDM") == 1)
{
ListUpdater lu = new ListUpdater();
this.Hide();
lu.ShowDialog();
this.Show();
}
else
{
MessageBox.Show("Private!");
}
}
EDIT2
Came up with the following possible solution but am nervous to use it because I am new at this and don't know what issues there might be. Any problems with just creating an event handler for form load?
namespace RunPackages
{
public partial class ListUpdater : Form
{
public ListUpdater()
{
InitializeComponent();
this.Load += new EventHandler(securityCheck);
}
private void securityCheck(object sender, EventArgs e)
{
if (MyGlobals.FormCheck("MDM1") == 0)
{
MessageBox.Show("Not Allowed!");
this.Close();
}
}
You can't dispose of the form within the form itself. The ShowDialog() method tries to access the form on exit for things such as DialogResult.
After a form has been disposed almost all of its methods can't be accessed (and most of its properties are invalid).
In your first line of btn_RunPkgs_Click() you create an object and you dispose it inside its constructor. Per se, even if pretty bad habit you may even call Dispose() from within constructor, it may even work but then you try to use such object ShowDialog() will generate ObjectDisposedException. Note that this code will also lead to same result (an exception):
RunPackages rp = new RunPackages();
rp.Dispose();
Yes you may check IsDisposed but that won't make code readable and problem (IMO) is you're mixing things. Constructor shouldn't contain such logic.
The point isn't just where you dispose your form. What's better is to don't even create such form (let me assume, because you call InitializeComponent(), that securityCheck() is called inside form constructor), for this you may use a factory static method:
public static bool TryShowDialog(Form currentForm)
{
if (MyGlobals.FormCheck("RUN_JOBS") != 1)
return false;
if (currentForm != null)
currentForm.Hide();
RunPackages dlg = new RunPackages();
dlg.ShowDialog();
if (currentForm != null)
currentForm.Show();
return true;
}
Your calling function will then be reduced to:
private void btn_RunPkgs_Click(object sender, EventArgs e)
{
RunPackages.TryShowDialog(this);
}
Note that such function is highly eligible for some refactoring (for example to extract code to hide/show existing form). Something like this:
public static bool ShowDialog<T>(Form currentForm, string authorizationId)
where T : Form, new()
{
if (MyGlobals.FormCheck(authorizationId) != 1)
return false;
if (currentForm != null)
currentForm.Hide();
T dlg = new T();
T.ShowDialog();
if (currentForm != null)
currentForm.Show();
return true;
}
Used like this (now code is reused everywhere):
SecurityHelpers.ShowDialog<RunPackages>(this, "RUN_JOBS");
Please note that calling code may be simplified (authorizationId may be an attribute on RunPackages, for example, and also currentForm can be deduced from current active form).
EDIT Calling Close() isn't better, if window handle has not been created (let's simplify little bit: it's created when window is shown) internally it'll call Dispose() (then above applies).
I would not try to disrupt the chaining of events that lead to the form creation.
The side effects are difficult to predict and what works today could not work in future versions.
Instead I would try a different approach
private void securityCheck()
{
if (MyGlobals.FormCheck("RUN_JOBS") == 1)
{
InitializeComponent();
}
else
{
Label message = new Label();
message.Dock = DockStile.Fill;
message.Text("You do not have permission to access this form!.");
message.TextAlign = ContentAlignment.MiddleCenter;
this.Controls.Add(message);
}
}
In this way I let the form show with just one label that covers the entire form surface with your message. The user could only close the form (provided that you have not removed the Control Box)
By the way, this has the advantage of avoiding dangerous oversights because it doesn't require any change on the calling code and the final effect is to effectively block the use of the form.
If you insist in closing the form during its constructor phase then you could get some advices from this question
I came up with the following, can anyone tell me if there are any issues with this?
namespace RunPackages
{
public partial class ListUpdater : Form
{
public ListUpdater()
{
InitializeComponent();
this.Load += new EventHandler(securityCheck);
}
private void securityCheck(object sender, EventArgs e)
{
if (MyGlobals.FormCheck("MDM1") == 0)
{
MessageBox.Show("Not allowed!");
this.Close();
}
}
etc...
Use a flag. For example change the code, like this:
public bool IsDisposed;
private void securityCheck()
{
if (MyGlobals.FormCheck("RUN_JOBS") == 1)
{
InitializeComponent();
}
else
{
//this.BeginInvoke(new MethodInvoker(this.Close));
//this.DialogResult = System.Windows.Forms.DialogResult.Cancel;
MessageBox.Show("You do not have permission to access this form!");
//this.Close();
this.Dispose();
this.IsDisposed = true;
}
}
Then:
private void btn_RunPkgs_Click(object sender, EventArgs e)
{
RunPackages rp = new RunPackages();
if(rp.IsDisposed)
return;
this.Hide();
rp.ShowDialog();//The error points to this line
this.Show();
}
Whilst developing a current project which contains a number of WinForms, I'm finding myself becoming cluttered with lines of code simply to handle open / close events for the forms. Currently I'm handling them like so..
//Declare forms
myForm mForm1;
myForm2 mForm2;
private void btnSomething_Click(object sender, EventArgs e)
{
if (mForm1 == null)
{
mForm1 = new myForm();
mForm1.FormClosed += new FormClosedEventHandler(mForm1_FormClosed);
mForm1.Show();
}
else
if (mForm1.WindowState == FormWindowState.Minimized)
mForm1.WindowState = FormWindowState.Normal;
mForm1.Focus();
}
void mForm1_FormClosed(object sender, FormClosedEventArgs e)
{
mForm1 = null;
}
And then another set of voids to handle each forms open / close. Now imagine that instead of 2 forms, I've got, say, 5 forms. Now I'm even more cluttered. Is there a way to generalize this to have all forms have the same event handlers?
I've thought of perhaps using the object sender in an "as" statement, but i'm not sure how i'd find the relevant declared form instance from there.
sender as (form)
Any ideas?
Make your Forms implementing some IFormWithMyEvents.
You can generalize that code easily:
//Declare forms
myForm mForm1;
myForm mForm2;
private void btnSomething_Click(object sender, EventArgs e)
{
ShowOrUpdateForm<myForm>(ref mForm1);
}
void ShowOrUpdateForm<T>(ref Form form) where T : Form
{
if (form == null)
{
form = new T();
form.FormClosed += new FormClosedEventHandler(mForm1_FormClosed);
form.Show();
}
else if (form.WindowState == FormWindowState.Minimized)
form.WindowState = FormWindowState.Normal;
form.Focus();
}
void mForm1_FormClosed(object sender, FormClosedEventArgs e)
{
// you cannot refactor this easily
if (sender == mForm1)
mForm1 = null;
else if (sender == mForm2)
mForm2 = null;
}
If you want to further generalize the closed event handler, you should consider moving forms' declarations to some sort of an array, list of dictionary. That way you can easily generalize that method.
EDIT: converted the ShowOrUpdateForm function to generic.