So in my program I have a settings page. On the settings page, there is an option to set the program "Always on Top". When this option is checked and unchecked, it properly saves the setting, but it does not actually change TopMost property itself.
The program's main form is called "MainForm", but the settings page is called "SettingsForm". How would I change the "TopMost" property on "MainForm", from within the "SettingsForm"?
You could create an event on Settings form:
public event EventHandler TopMostEvent;
private void OnTopMostEvent()
{
if (TopMostEvent != null)
{
TopMostEvent(this, EventArgs.Empty);
}
}
On CheckedChanged event call the method after saving settings:
OnTopMostEvent();
And in Main form subscribe to the event and set the forms TopMost property
One approach would be to simply give SettingForm a reference to MainForm, e.g. via a constructor parameter which is then stored to a field where it can later be accessed when necessary.
For example:
public class SettingsForm
{
public SettingsForm(MainForm mainForm)
{
this.mainForm = mainForm;
}
public void Apple()
{
this.mainForm.TopMost = true;
}
private readonly MainForm mainForm;
}
public class MainForm
{
public void Banana()
{
var settingsForm = new SettingsForm(this);
settingsForm.ShowDialog();
}
}
(However, it may not be necessary to do this if the owner of SettingsForm is already the insntance of MainForm but this I cannot tell from what you have given.)
This is a good place for a mediator pattern. (Similar to a controller) The idea is you have one object that creates all of your windows and passes a reference to itself into each form through the constructor. You can call a method in the mediator from either form and the mediator will focus the MainForm. It's a very common practice in Windows Forms.
So you'll make a mediator class like so:
public class MyMediator
{
Form mainForm {get;set;}
Form settingsForm{get;set;}
public MyMediator()
{
mainForm = new MainForm(this);
mainForm.Show();
}
...
public FocusMainForm() // call this from settings form
{
mainForm.TopMost = true;
}
}
Related
I was wondering how you would close the Form that is currently in focus or the one which a control is contained in. For example, I have an imported header with a menu that I import into all forms in my application.
This is the (simplified) code in my Header class:
public static Panel GetHeader()
{
...
menuItem.Text = "Menu Item";
menuItem.Name = "Next form to open";
menuItem.Click += toolStrip_Click;
...
}
public static void toolStrip_Click(object sender, EventArgs e)
{
ToolStripMenuItem menuItem = sender as ToolStripMenuItem;
NavigationClass.SaveNextForm(menuItem.Name);
}
The navigation class is just something I made which will select the next form to open but I couldn't find anything to then close the current one (since Close() isn't an option due to it being imported with Controls.Add(HeaderClass.GetHeader))
Edit
Just to make clear, this form is in another file which is just a normal class file. That's where the difficulty lies because I'm trying to avoid a severe violation of the DRY principle
Don't use static handlers as #Hans Passant suggests. That is important.
Try sending your main form to your class as a parameter, and store it in that class. This can be done either when you are instantiating your class, or after that. Then, when you need to close the form, call it's Close method. Since you don't include your codes in more details, here is my example with some assumptions.
public class MainForm : Form
{
private HeaderClass HeaderClass;
public MainForm()
{
HeaderClass = new HeaderClass(this);
}
}
public class HeaderClass
{
private MainForm MainForm;
public HeaderClass(MainForm mainForm)
{
MainForm = mainForm;
}
public void MethodThatYouNeedToCloseTheFormFrom()
{
...
MainForm.Close();
...
}
}
Let us know if you require any more elaboration.
For example after creating a new Windows Form project I have my class called Form1.cs and from that form I can simply start typing the name of a form control and it will auto populate the form control variable names and I am able to use them in the class. However I have other classes that need to be able to access these form control variables as well, but they are not accessible.
Make them public if they are going to be used in another assembly, or internal if they are going to be used in the same project. Making them static means you don't have to pass your Form1 into the other classes.
Example... Say your Form1 has a string that contains the text you display in the title bar. Making it internal static, like this:
internal static readonly string MsgBox_Title = " Best Application Evar!";
lets you access it from other classes like this:
Form1.MsgBox_Title
It doesn't have to be readonly; that's just an example I pulled from an old app...
If you don't want static variables, you'll have to pass in an instance of Form1.
public class SomeClass
{
private Form1 m_Form1;
public SomeClass(Form1 form1)
{
m_Form1 = form1;
}
private void someMethod()
{
string localValue = m_Form1.SomeMemberStringVariable;
}
}
It's a very contrived example, but hopefully you get the idea.
If you want to call the Refresh method from a class instantiated from Form1, you could use an event in the child class to notify Form1.
Example:
This Form1 has a button that I use to show a secondary form.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnShowPopup_Click(object sender, EventArgs e)
{
PopupForm f = new PopupForm();
f.CallRefreshHandler += PopupForm_CallRefreshHandler;
f.ShowDialog();
}
private void PopupForm_CallRefreshHandler(object sender, EventArgs e)
{
Refresh();
}
}
The secondary form, "PopupForm", has a button that I use to raise an event that the Form1 is subscribed to, and lets Form1 know to call Refresh.
public partial class PopupForm : Form
{
public event EventHandler CallRefreshHandler;
public PopupForm()
{
InitializeComponent();
}
private void btnRaiseEvent_Click(object sender, EventArgs e)
{
EventHandler handler = CallRefreshHandler;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
Hope this helps.
Create an object of that class & start using those variables like this
Form1 fm = new Form1();
string abc = fm.VAR;
Define a public property in your form.
public string MyProp { get; set; }
Form1 frm = new Form1();
frm.MyProp = "Value";
Or define the property as static to avoid having to instantiate Form1:
public static string MyProp { get; set; }
Form1.MyProp = "Value";
I ran into this issue recently. I was keeping some methods in a separate class. Maybe not a good design decision in my case, I'm not sure yet. And these methods sometimes needed to communicate with controls in the main Form1. For example, to write to textBox1.
Turns out easy enough. Just write your method signature to include a TextBox instance. For example you pass textBox1 in and inside the method you refer to it as tb. Then when you call that method (even though it is in another class) you set the tb.Text property to whatever you like and it will show on textBox1.
This makes sense when you consider that control is just a special kind of object, graphically represented in the Form. When you pass it as an argument to a method in another class or the same class, you are actually passing the reference. So writing text to it in the method call will write text to the original control.
I have a class 'App' which has instances of both a 'DeviceManager' class and a windows form 'MainForm' stored as fields.
MainForm is made visible by clicking a system tray icon. DeviceManager has Docked and Undocked methods, with Docked starting a synchronization operation. The Docked method should only start the operation if the MainForm is not visible.
DeviceManager doesn't have access to App's members, so it can't use App's reference to MainForm to check the form's status. Having App pass itself into DeviceManager's constructor seems like a lot of coupling when DeviceManager has no other need for such a reference (MainForm and DeviceManager are thus far unaware of each other).
I'm now considering having the setter of the App.IsUserActive property raise an event that DeviceManager can use to maintain its own 'IsUserActive' field.
Are there any other approaches I could look into?
Edit: added code to illustrate:
internal class App
{
private DeviceManager _deviceMgr;
private MainForm _mainForm;
internal App()
{
_deviceMgr = new DeviceManager();
_mainForm = new MainForm { Visible = false };
}
}
internal class DeviceManager
{
private void Docked()
{
if (!_mainForm.Visible) //can't see MainForm or App from here
{
Connect();
StartSynchronization();
}
}
private void Undocked()
{
Disconnect();
}
}
There is a global reference to the forms you can use.
Here's a quick example:
//Inside of DeviceManager class
private bool CheckFormVisibility<TForm>() where TForm : Form
{
TForm form = System.Windows.Forms.Application.OpenForms.OfType<TForm>().SingleOrDefault();
return form != null && form.Visible;
}
Then call CheckFormVisibility<MyForm>() or remove the generics and use specifically for your MyForm.
**I'm going under the assumption here that you will only have zero/one instance of a form.
I have a problem concerning delegates in a Windows.Forms application.
There are two forms:
the main form, which has a button named "Settings".
the "settings" form, this is the "child" form.
When I click the "Settings" button in the main form, it opens an instance of the Settings form.
My problem is that I need to pass a variable to the Settings form, when I open it. So that the new form will show the variable text. I don't know how to retrieve the information in the child "Settings" form. I did this by following a tutorial online and could not understand from the tutorial how to read the info in the destination form.
Here's what I've done so far, the code in the main form:
public partial class MainForm : Form
{
/// <summary>
/// delegate to send data between forms
/// </summary>
public delegate void PageInfoHandler(object sender, PageInfoEventArgs e);
/// <summary>
/// event of the delegate
/// </summary>
public event PageInfoHandler PageInfoRetrieved;
//other stuff, events blabla
private void toolStripBtnSettings_Click(object sender, EventArgs e)
{
PageInfoEventArgs args = new PageInfoEventArgs(SomeString);
this.OnPageInfoRetrieved(args);
SettingsForm settingsForm = new SettingsForm();
settingsForm.ShowDialog();
}
private void OnPageInfoRetrieved(PageInfoEventArgs args)
{
if (PageInfoRetrieved != null)
PageInfoRetrieved(this, args);
}
}
Pass any information you want to in to the constructor of Settings form, and provide accessor methods for things you need out of there.
public class SettingsForm : WinForm
{
private string m_Data;
private int m_nExample = 0;
// ctor
public SettingsForm(string _data)
{
m_Data = data; // you can now use this in SettingsForm
} // eo ctor
public int Example {get{return(m_nExample);} }
} // eo class SettingsForm
In the above "example" you can construct a SettingForm with a string and get at an integer it may use. In your code:
private void toolStripBtnSettings_Click(object sender, EventArgs e)
{
PageInfoEventArgs args = new PageInfoEventArgs(SomeString);
this.OnPageInfoRetrieved(args);
SettingsForm settingsForm = new SettingsForm("some data to pass");
settingsForm.ShowDialog();
int result = settingsForm.Example; // retrieve integer that SettingsForm used
}
The Setttings form is a class. It's yours now and you can do what you like with it. So add a parameter (or however many you want) to its constructor. Then in your MainForm call SettingsForm(whatever) and you're all set.
I would suggest adding a property to SettingsForm.
Then, call it like this:
SettingsForm settingsForm = new SettingsForm();
settingform.myProperty = myPropertyvalue;
settingsForm.ShowDialog();
Why don't you add a constructor to your settings form which takes parameters and pass in any data you need there?
You can create a parametrized constructor for your settings form which accepts the text, and sets it to a property in the form
public partial class SettingsForm : Form
{
public string DisplayText {get;set;}
public SettingsForm(string text)
{
DisplayText = text;
}
}
then, you'd just initialize the settings from like this (From your mainform)
var settingsForm = new SettingsForm("my init text");
your settings form will be properly initialized, and you have the desired text in the DisplayText property ready to use
How do i show a from that have been hidden using
this.Hide();
I have tried
MainMenuForm.Show();
and this just says i need an object ref. I then tried:
MainMenuForm frmMainMenu = new MainMenuForm();
frmMainMenu.Show();
Which seems to show the appropriate form. But when you exit the app, it is still held in memory because it hasn't shown the form that was hidden, instead it has shown a new version of the form. In effect having 2 instances of the form (one hidden, one visible).
Just to clarify, the MainMenuForm is the startup form. When (for example) Option 1 is clicked, the MainMenuForm then hides itself while opening up the Option 1 form. What i would like to know is how to i make the Option 1 form that the MainMenuForm opens "unhide" the MainMenuForm and then close itself.
What's the correct procedure here?
Thanks in advance.
When you do the following:
MainMenuForm frmMainMenu = new MainMenuForm();
frmMainMenu.Show();
You are creating and showing a new instance of the MainMenuForm.
In order to show and hide an instance of the MainMenuForm you'll need to hold a reference to it. I.e. when I do compact framework apps, I have a static classes using the singleton pattern to ensure I only ever have one instance of a form at run time:
public class FormProvider
{
public static MainMenuForm MainMenu
{
get
{
if (_mainMenu == null)
{
_mainMenu = new MainMenuForm();
}
return _mainMenu;
}
}
private static MainMenuForm _mainMenu;
}
Now you can just use FormProvider.MainMenu.Show() to show the form and FormProvider.MainMenu.Hide() to hide the form.
The Singleton Pattern (thanks to Lazarus for the link) is a good way of managing forms in WinForms applications because it means you only create the form instance once. The first time the form is accessed through its respective property, the form is instantiated and stored in a private variable.
For example, the first time you use FormProvider.MainMenu, the private variable _mainMenu is instantiated. Any subsequent times you call FormProvider.MainMenu, _mainMenu is returned straight away without being instantiated again.
However, you don't have to store all your form classes in a static instance. You can just have the form as a property on the form that's controlling the MainMenu.
public partial class YourMainForm : Form
{
private MainMenuForm _mainMenu = new MainMenuForm();
protected void ShowForm()
{
_mainMenu.Show();
}
protected void HideForm()
{
_mainMenu.Hide();
}
}
UPDATE:
Just read that MainMenuForm is your startup form. Implement a class similar to my singleton example above, and then change your code to the following in the Program.cs file of your application:
Application.Run(FormProvider.MainMenu);
You can then access the MainMenuForm from anywhere in your application through the FormProvider class.
The simplest and easiest way is to use LINQ and look into the Application.OpenForms property. I'm assuming you have only 1 instance of the form (hopefully!), otherwise make sure to have to have some public property on the hidden form to be able to differentiate it.
The following code will un-hide the form for you:
var formToShow = Application.OpenForms.Cast<Form>()
.FirstOrDefault(c => c is MainMenuForm);
if (formToShow != null)
{
formToShow.Show();
}
You need to keep a reference to the first form when it's created and then the code that holds that reference can call Show on it.
If you don't open that form from somewhere but it's set as the startup form, then you either need to change it so that you have a Main method that opens that form or you can have that form store a reference to itself somewhere that can be accessed from other places.
For example, an quick and ugly way would be to, add a public static property to your mainform and then when you hide the form it also writes this to that property which can then be retrieved when needed by other parts of the code.
Practically This works for me....
public class MainWindow : Form
{
Form _mainMenuForm = new MainMenuForm();
}
calling it through a button click event.
private void buttonclick()
{
if (_mainMenuForm.Visible)
{
_mainMenuForm.Visible = false;
}
else
{
_mainMenuForm.Visible = true;
}
}
Store a reference to the form and call .Hide() and .Show() on that.
For example:
public class MainWindow : Form
{
private Form _mainMenuForm = new MainMenuForm();
public void btnShowMenuForm_Click(...)
{
_mainMenuForm.Show();
}
public void btnHideMenuForm_Click(...)
{
_mainMenuForm.Hide();
}
//etc
}
This example assumes you have a form which is launching the MainMenuForm.
Call the referenced form.
Like:
Calling parent
----------
public MyForm f {get;set;}
void DoStuff()
{
f = new MyForm();
f.Show();
}
MyForm
----------
void DoOtherStuff()
{
this.hide();
}
Parent
----------
void UnHideForm()
{
f.show();
}
Another simpler method to achieve this is to loop through the open forms to see which are still running and open it...
foreach (Form oForm in Application.OpenForms)
{
if (oForm is MainMenuForm)
{
oForm.Show();
break;
}
}