C# Trying to access the location of a panel's parent - c#

I have a main form with a tab control on it. The tabs get populated by adding panels from other forms within the solution. One of these panels has some code that will pop up an options window. I want that window to align itself to the top right hand side of the main form. To do this I need the location and size of the main form. However, I cannot seem to access any property that will tell one of the panels what the location of that main form is.
I've tried things like this.Parent, this.ParentForm and this.GetContainerControl(). They all return null.
Any ideas?
Addendum
//Code for the main form:
namespace WinAlignTest {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
tabControl1.TabPages[0].Controls.Add(new SomeApplication().panel1);
}
}
}
//Code that shows the option window
namespace WinAlignTest {
public partial class SomeApplication : Form {
private ApplicationOptions Options;
public SomeApplication() {
InitializeComponent();
Options = new ApplicationOptions();
}
private void button1_Click(object sender, EventArgs e) {
Options.Show();
//This will always move the location to {0,0}
Options.Location = new Point(base.Location.X,base.Location.Y);
}
}
}

I'm confused, you seem to be adding a panel which belongs to SomeApplication to Form1. I would suggest you actually make SomeApplication a UserControl instead of a form:
//Code for the main form:
namespace WinAlignTest {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
tabControl1.TabPages[0].Controls.Add(new SomeApplication());
}
}
}
//Code that shows the option window
namespace WinAlignTest {
public partial class SomeApplication : UserControl {
private ApplicationOptions Options;
public SomeApplication() {
InitializeComponent();
Options = new ApplicationOptions();
}
private void button1_Click(object sender, EventArgs e) {
Options.Show();
// You might need to use PointToScreen here
Options.Location = this.Location;
}
}
}

Check out
Application.OpenForms
That should give you access to what you want.

the base identifier accesses a parent element.
Two possible problems: First, your constructors don't explicitly extend your base constructor. it would look like this:
public Form1():base(){}
I still recommend making getter methods in the Form1 class. It would look something like this:
public int Form1Location
{
get{return /*FormLocation*/}
}
and call it from WinAlignTest
Let me know if this works.

Related

Close form currently in focus

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.

Using Extensions with the Static Class System.Windows.Forms

I'm new to C# so bear with me, I'm trying to add methods to the Forms class so that I can show and hide other forms from within a different form if that makes sense. In my extension I have:
namespace ExtensionMethods
{
public static partial class FormExtentsion : Form
{
public static void HideForm(this Form frm)
{
frm.Hide();
}
public static void UnhideForm(this Form frm)
{
frm.Show();
}
}
}
And in my project I have:
private void bnTrBack_Click(objects sender, EventArgs e)
{
Main.UnhideForm();
this.Close();
}
Where Main is my main form. Is there a way to have a form open/close another form? Any help is much appreciated!!
As #CEvenhuis pointed out in a question comment, you need an instance of the main form.
(And, you don't need extension methods at all. Never do—They just allow calling code to look and feel different. But, in this case, in the code you've shown, you are just giving pet names to well-known, existing methods.)
Anyway, in the "child" form, you could have a field to refer to the instance of the main form.
Form _parent;
And use it like
private void bnTrBack_Click(objects sender, EventArgs e)
{
_parent.Show();
Close();
}
Or, assuming the child is only ever a child of the main form,
Main _main;
private void bnTrBack_Click(objects sender, EventArgs e)
{
_main.Show();
Close();
}
The question would be how to set the field.
It can be set in a constructor:
ReadOnly Main _main;
And change the designer-generated code from:
public Child()
{
InitializeComponent();
}
to
public Child(Main main)
{
InitializeComponent();
_main = main;
}
Stepping back a bit, instead of hiding the main form, you could instead—if appropriate— show the child form as a modal dialog and receive back a simple result after it closes:
var result = new Child().ShowDialog();
In general, there are two things to evaluate concerning the options:
User experience: Are the controls presented to the users in a way they can understand and in a way that allows them to follow desired workflows?
Coupling between classes: Which classes depend on which classes and in what way? Is there a good plan for passing data and control?

How can I make my Form Control variables acessible to classes other than my Form class?

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.

How to update a control in MDI parent form from child forms?

I looked to some similar questions but I didn't really get my answer, so I ask again hopefuly someone can explain it.
The situation:
I have a MDI form that has some menues and a status bar and stuff like that. Is the only way of altering text for status bar and doing other things to the parent form is to call it as static? Or if not, can you please give an example for updating (for example) status bar that exist in parent form within the child forms?
Thanks!
You need to make the child forms take a parent form instance as a constructor parameter.
The children can save this parameter to a private field, then interact with the parent at will later.
For optimal design, you should abstract the parent from the child through an interface implemented by the parent, containing methods and properties that do what the children need. The children should then only interact with this interface.
public interface IChildHost {
void UpdateStatusBar(string status);
//Other methods & properties
}
public partial class ParentForm : IChildHost {
public void UpdateStatusBar(string status) {
...
}
//Implement other methods & properties
}
public partial class ChildForm {
readonly IChildHost host;
public ChildForm(IChildHost parent) {
this.host = parent;
}
}
The Form class already exposes a property MdiParent ensure the parent forms IsMdiContainer property is set accordingly.
Another option is to use events (you can build these events into a base class and let all your child forms inherit from it):
// Code from Form 1
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form2 objForm2 = new Form2();
objForm2.ChangeStatus += new ChangeStatusHandler(objForm2_ChangeStatus);
objForm2.Show();
}
public void objForm2_ChangeStatus(string strValue)
{
statusbar.Text = strValue;
}
}
// Code From Form 2
public delegate void ChangeStatusHandler(string strValue);
public partial class Form2 : Form
{
public event ChangeStatusHandler ChangeStatus;
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
if (PassValue != null)
{
PassValue(textBox1.Text);
}
}
}

How to call an EventHandler in a parent class

I have added an EventHandler for the Click-event to a picturebox but on runtime this handler is never called (the debugger shows me that it is added to the control directly but when I click on the picturebox nothing happens).
I assume it has something to do with my inheritance. I have a usercontrol called AbstractPage (its not really abstract since the designer doesnt like that) which only consists of a heading and this picturebox but it provides quite some functions the actual pages rely on.
#region Constructor
public AbstractPage()
{
InitializeComponent();
lblHeading.Text = PageName;
picLock.Click += new EventHandler(picLock_Click);
}
#endregion
#region Events
void picLock_Click(object sender, EventArgs e)
{
...do some stuff
}
#endregion
The page implementations just inherit this class and add their controls and behavior. We recently figured out that subclassing UserControl is not performant and we lose some performance there, but its the best way to do it (I dont want to c&p function for 25 pages and maintain them).
My pageA looks like this
public partial class PageA : AbstractPage
{
#region Constructor
public PageA()
{
// I dont call the base explicitely since it is the
// standard constructor and this always calls the base
InitializeComponent();
}
#endregion
public override string PageName
{
get { return "A"; }
}
public override void BindData(BindingSource dataToBind)
{
...
}
Anyway, the picLock_Click is never called and I dont know why?
The pages are all put into a PageControl which consists of a TreeView and a TabContainer where the pages are put once I call addPage(IPage)
public partial class PageControl {
...
protected virtual void AddPages()
{
AddPage(new PageA());
AddPage(new PageD());
AddPage(new PageC());
...
}
protected void AddPage(IPage page)
{
put pagename to treeview and enable selection handling
add page to the tabcontainer
}
Thanks in advance
If I understand your problem correctly, this worked for me out of the box (using VS2k8). My code:
public partial class BaseUserControl : UserControl
{
public BaseUserControl()
{
InitializeComponent(); //event hooked here
}
private void showMsgBox_Click(object sender, EventArgs e)
{
MessageBox.Show("Button clicked");
}
}
public partial class TestUserControl : BaseUserControl
{
public TestUserControl()
{
InitializeComponent();
}
}
I moved the TestUserControl to a form, clicked the button and got the message box as expected. Can you paste some more code, e.g. how do you use your AbstractPage?
I found the problem. We are using the Infragistics WinForms but in that case I used the standard picturebox. I replaced it with the UltraPictureBox and now it works.

Categories