ShowDialog with Parent still enabled - c#

In one of our apps we want to want to limit the user from opening other menu items when an existing menu item is already open. We are currently doing this:
private void menuItem1_Click(object sender, EventArgs e)
{
Myform f = new MyForm();
f.ShowDialog(this);
}
However in doing this, we lose the ability to interact at all with the parent window because internally, the parent.enabled property was set to false. Using the code above, if the user has menu item open and wants to move the parent window to see something on their desktop, they first must close the menu item, move the parent, and reopen the menu item.
I have come up with the follow method of doing the UI in a backgroundworker
public class BaseForm : Form
{
private bool _HasChildOpen;
protected BackgroundWorker bgThead;
public BaseForm()
{
_HasChildOpen = false;
bgThead = new BackgroundWorker();
bgThead.DoWork += new DoWorkEventHandler(OpenChildWindow);
bgThead.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.ClearChildWindows);
}
protected void ClearChildWindows(object sender, RunWorkerCompletedEventArgs e)
{
_HasChildOpen = false;
}
public void OpenChildWindow(object sender, DoWorkEventArgs e)
{
if (!_HasChildOpen)
{
Form f = (Form)e.Argument;
f.StartPosition = FormStartPosition.CenterScreen;
f.ShowDialog();
}
}
}
and then each menu item has the following code
private void menuItem1_Click(object sender, EventArgs e)
{
if (!bgThead.IsBusy)
{
bgThead.RunWorkerAsync(new Myform());
}
}
but this approach is a big no no. However, using invoke seems to get me back where I started:
private void doUIWork(MethodInvoker d)
{
if (this.InvokeRequired)
{
this.Invoke(d);
}
else
{
d();
}
}
public void OpenChildWindow(object sender, DoWorkEventArgs e)
{
if (!_HasChildOpen)
{
doUIWork(delegate() {
Form f = (Form)e.Argument;
f.StartPosition = FormStartPosition.CenterScreen;
f.ShowDialog();
});
//Form f = (Form)e.Argument;
//f.StartPosition = FormStartPosition.CenterScreen;
//f.ShowDialog();
}
}
How do I properly limit the user to just one menu item open, but at the same time leave the parent enabled such that it can be moved resized etc?

You will need to programmatically disable menu strip behavior once one of the forms is open. So if you have Form1 and Form2, (with a menuStrip on Form1 and toolStripMenuItem1, toolStripMenuItem2 on the menuStrip):
private void menuItem1_Click(object sender, EventArgs e)
{
var f2 = new Form2();
f2.FormClosing += f2_FormClosing;
f2.Show();
this.menuStrip1.Enabled = false;
}
private void menuItem2_Click(object sender, EventArgs e)
{
var f2 = new Form2();
f2.FormClosing += f2_FormClosing;
f2.Show();
this.menuStrip1.Enabled = false;
}
void f2_FormClosing(object sender, FormClosingEventArgs e)
{
this.menuStrip1.Enabled = true;
}
using the Show() method instead of ShowDialog() enables interaction with the parent control, though you will need to manually disable/enable behavior depending on when the child control is shown or not.

Related

How to get a button to toggle another button on a separate form?

I am trying to get it so when a person in the administration panel pushes the "Lock System" on the admin form it disables the buttons on "Form1". I have set the button to public and changed it to a public void in the code.
Here is what I have tried.
Admin Panel Code:
private void Button7_Click(object sender, EventArgs e)
{
((Form1)this.Owner).button1.Enabled = false;
}
Form1 Code:
public void Button1_Click(object sender, EventArgs e)
{
var newwindow = new CanCad();
newwindow.Show();
}
Here is a screenshot of the error I get: http://prntscr.com/ptkkm3
You're trying to use the Owner property of the second form but it was never set. To set the Owner property, you should pass the instance of the first form to the .Show() method:
public void Button1_Click(object sender, EventArgs e)
{
var newwindow = new CanCad();
newwindow.Show(this); // <------ notice the difference.
}
Or you could set the property manually if you like:
newwindow.Owner = this;
newwindow.Show();
Then, you can use your original code in the second form as usual:
private void Button7_Click(object sender, EventArgs e)
{
((Form1)this.Owner).button1.Enabled = false;
}
A further improvement would be to use the as operator to make sure that the owner is of the right type:
Form1 frm = this.Owner as Form1;
if (frm != null) frm.button1.Enabled = false;

How to have Main form's menu process events on OwnedForms?

I have a Main Form with a MenuStrip on it, and I use that MenuStrip to open new owned Forms like so:
var target = new Target();
target.Owner = this;
target.Show();
This works exactly how I want it to: the Forms are always shown in front of the Main Form.
The issue that I run into is that, when one of these owned Forms has the focus, I can't access the MenuStrip via keyboard. I'd like CTRL+S to trigger the Save functionality, the same as it does when the Main Form has the focus.
Is this possible? Is there a better way to approach this?
Sorry for the delay, but if you're still having issues or looking for a different method, see below.
In your MainForm:
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
ChildForm child = new ChildForm();
// KeyPreview can be set in the properties of the child form instead
child.KeyPreview = true;
child.KeyPressed += Child_KeyPressed;
child.ShowDialog();
}
private void Child_KeyPressed(object sender, KeyEventArgs e)
{
if (e.Control && e.KeyCode == Keys.S)
{
// Save Pressed
}
}
}
and then in your Child Form:
public partial class ChildForm : Form
{
public event EventHandler<KeyEventArgs> KeyPressed;
public ChildForm()
{
InitializeComponent();
}
private void Child1_KeyUp(object sender, KeyEventArgs e)
{
KeyPressed?.Invoke(sender, e);
}
}
Thanks to Troy Mac1ure for the direction. Here's the solution that lets me use the ShortCutKeys from the main menu.
ownedForm.KeyPreview = true;
ownedForm.KeyDown += OwnedForm_KeyDown;
private void OwnedForm_KeyDown(object sender, KeyEventArgs e)
{
if (e.Control)
{
foreach (ToolStripMenuItem menuItem in menu.Items)
{
foreach (ToolStripMenuItem item in menuItem.DropDownItems.OfType<ToolStripMenuItem>())
{
if (item.ShortcutKeys == e.KeyData)
{
item.PerformClick();
return;
}
}
}
}
}
This doesn't handle Alt menu activation, but Paint.NET doesn't handle that either, so I view that as a nice-to-have.

Wait Form C# On Panel

I have 3 forms. Names: MainScreen, LoadingForm, MoviesInfo.
When I press the button on the MainScreen, it is doing some works and the LoadingForm is loading inside a panel on the MainScreen.I want to do when works done, show the MoviesInfo Form on the same panel on the MainScreen or panel on the LoadingForm. How can I do that?
I add the forms on the panel like that.
public static void AddFormToPanel(Form frm, Panel panel)
{
frm.TopLevel = false;
panel.Controls.Add(frm);
frm.Show();
frm.Dock = DockStyle.Fill;
frm.BringToFront();
}
//Loading Form
public partial class LoadingForm : Form
{
public Action Worker { get; set; }
public LoadingForm(Action worker)
{
InitializeComponent();
if (worker == null)
{
throw new ArgumentNullException();
}
Worker = worker;
}
private void btnCancel_Click_1(object sender, EventArgs e)
{
this.Close();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
Task.Factory.StartNew(Worker)
.ContinueWith(t => { this.Close(); }, TaskScheduler.FromCurrentSynchronizationContext());
}
}
MainScreen Form
private void MovieOnButtonClick(object sender, EventArgs eventArgs)
{
using (loading = new LoadingForm(getMovieData))
{
loading.ShowDialog(this);
}
AddFormToPanel(moviesInfo, panelMain);
}
I don't want this line loading.ShowDialog(this); I want to add loading form inside the panel.
Move the action and the control to the MainForm:
private async void MovieOnButtonClick(object sender, EventArgs eventArgs)
{
var loadingForm = new LoadingForm(); // create a dummy loadingForm
AddFormToPanel(loadingForm, panelMain);
var work = Task.Factory.StartNew(Worker); // Worker = GetMovies or so
await work;
AddFormToPanel(moviesInfo, panelMain);
loadingForm.Dispose();
}
Remove all logic and events from the LoadingForm.
And it is better to use UserControl than Forms to place in that Panel.

New form fails to appear

Can someone explain why my new form doesn't appear? The old form closes but it isn't replaced by my new one:
namespace Pong
{
public partial class Menu : Form
{
public Menu()
{
InitializeComponent();
}
private void pictureBox1_Click(object sender, EventArgs e)
{
}
private void PlayButton_Click(object sender, EventArgs e)
{
PongForm form = new PongForm();
form.Show();
this.Close();
}
private void ExitButton_Click(object sender, EventArgs e)
{
this.Close();
}
}
}
Is "Menu" the startup form for your application? If yes, then when it closes the entire application closes.
One solution would be to hide the current form, display "form" with ShowDialog(), then call Close():
private void PlayButton_Click(object sender, EventArgs e)
{
this.Visible = false; // hide the current form
Application.DoEvents();
PongForm form = new PongForm();
form.ShowDialog(); // code stops here until PongForm is dismissed
this.Close(); // now close the form (and presumable the whole app)
}

Closing event handlers C#

I have two forms, Form 2 is inheriting from Form 1.
What I need to do is that when I close both Form 1 and Form 2 another form which asks if user is sure to quit appears. Then if user clicks Yes, another form which asks if the user wants to save the game appears if and only if the form which the user closes is Form 2 and not Form 1 since for Form 1 there is no saving necessary.
This is what I managed to do:
// These are the Form 1 closing and closed event handlers:
private void GameForm_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = true;
SureClose sc = new SureClose();
sc.StartPosition = FormStartPosition.CenterScreen;
sc.Show();
}
private void GameForm_FormClosed(object sender, FormClosedEventArgs e)
{
MainMenu menu = new MainMenu();
menu.Show();
}
Then in Sure Close: // Please note that Tournament is Form 2 inheriting from GameForm (Form 1)
private void yesButton_Click(object sender, EventArgs e)
{
this.Hide();
if (GameForm.ActiveForm is Tournament)
{
SaveGame sg = new SaveGame();
sg.StartPosition = FormStartPosition.CenterScreen;
sg.Show();
}
else
{
GameForm.ActiveForm.Close();
}
}
private void noButton_Click(object sender, EventArgs e)
{
this.Hide();
}
// This is the SaveGame Form:
private void saveButton_Click(object sender, EventArgs e)
{
// Still to do saving!
}
private void dontSaveButton_Click(object sender, EventArgs e)
{
this.Hide();
GameForm.ActiveForm.Close();
}
The problem is that when in the yesButton event handler in SureClose Form I have GameForm.ActiveForm.Close(), this is going back to the GameForm Closing event handler therefore the SureClose dialog is appearing again.
I tried doing: if (e.CloseReason() == CloseReason.UserClosing)
but obviously it doesn't work either because the reason of closing will always be the user :/
How can I solve this?
Thanks a lot for any help !
Form1 :
private void GameForm_FormClosing(object sender, FormClosingEventArgs e)
{
if(SureClose())
{
SaveChanges();
}
else
{
e.Cancel = true;
}
}
private bool SureClose()
{
using(SureClose sc = new SureClose())
{
sc.StartPosition = FormStartPosition.CenterScreen;
DialogResult result = sc.ShowDialog();
if(result == DialogResult.OK)
{
return true;
}
else
{
return false;
}
}
}
protected virtual void SaveChanges()
{
}
Form2:
protected override void SaveChanges()
{
using(SaveGame sg = new SaveGame())
{
sg.StartPosition = FormStartPosition.CenterScreen;
DialogResult result = sg.ShowDialog();
if(result == DialogResult.OK)
{
//saving code here
}
}
}
SureClose form and SaveGame form:
private void yesButton_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.OK;
}
private void noButton_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.Cancel;
}

Categories