Winforms Location - c#

I have an app with 2 forms, the main window and a second Form.
What I want is to open up the second Form on a button click and it's location must be right beside the main form (so if the main form is 600px wide, the X of the new Form will be main.X + 600)
Have tried this but it doesn't seem to take, it opens on top of the main form still:
private void button1_Click(object sender, EventArgs e)
{
var form = new SecondForm();
var main = this.Location;
form.Location = new Point((main.X + 600), main.Y);
form.Show();
}
Is Location not the correct attribute?

Set your form's StartPosition to FormStartPosition.Manual. You can do it in the designer or from the constructor:
StartPosition = FormStartPosition.Manual;

Clearly you didn't count on the StartPosition property. Changing it to Manual is however not the correct fix, the second form you load may well rescale itself on another machine with a different video DPI setting. Very common these days. Which in turn can change its Location property.
The proper way is wait for the Load event to fire, rescaling is done by then and the window is not yet visible. Which is the best time to move it in the right place. StartPosition no longer matters now. Like this:
var frm = new SecondForm();
frm.Load += delegate {
frm.Location = new Point(this.Right, this.Top);
};
frm.Show();

Location is right property, but you must set
Form.StartPosition = FormStartPosition.Manual;
too.

Related

C# Using One Panel As a Placeholder For Multiple Forms

I apologize if this has been addressed already, but I could not find a case that fit my exact situation. So here goes...
I have a MainForm that contains a toolStrip1 docked to the left that functions as a vertical navigation bar. I have a panel (pnlMain) filling up the remainder of the form. I want to use pnlMain to display different forms which are made up of win form classes. Right now, I can click on the labels/buttons on toolStrip1 to display different forms within pnlMain.
private void tsLblCustomers_Click(object sender, EventArgs e)
{
hidePanels();
CustomerReport cr = new CustomerReport();
cr.TopLevel = false;
cr.AutoScroll = true;
cr.BackColor = Color.White;
pnlMain.Controls.Add(cr);
cr.Show();
}
What I want to do now is display additional forms within pnlMain by clicking on a button on another form rather than a label/button on toolStrip1. Some of my forms are as follows: CustomerReport, AddCustomer, EmployeeReport, AddEmployee. The Report forms are linked to my tool strip buttons. The Add forms are linked to buttons on the Reports forms. I tried several things including the following:
1) On CustomerReport, I tried creating an instance of MainForm, then I'll create an instance of AddCustomer, and then add that instance to the panel on MainForm.
2) I also tried creating a method in MainForm to create the instance of AddCustomer, and then call that method from the Add button on CustomerReport. Even though the code was the same as the toolstrip buttons on MainForm, it did not work.
I tried different variations of hiding forms, showing forms, clearing the panel, setting Visible to true or false, and I can't get it to work right. In some cases, I've managed to hide the CustomerReport, but AddCustomer will not come up. At some point I think I created a NEW instance of MainForm and my code wasn't impacting the original form that is already open. I'm just lost. Should I be using a different design? Originally I set up my application to just hide one form then show the other but I read that that is a 'terrible design'.
This sounds very similar to this thread here: Creating Form Inside the Form
You'd want to look into MDI.
Although it sounds like you're aiming for one cohesive interactive window. Otherwise, if you just want separate windows to popup, you can create properties within that other form and read them after returning a DialogResult. I'm not sure why this would be bad design without knowing more about the context of the program.
//Optionally do a hide(); here.
AddCustomer customer = new AddCustomer();
DialogResult result = customer.ShowDialog();
if(result == DialogResult.OK)
{
var name = customer.Name;
//More properties or whatever here.
}
//The properties would still be accessible here, too.
I ended up keeping the toolstrip nav bar on the left side of the primary window, and I created a panel in the main part of the window. All forms are displayed in the panel. Each time one of the label options in the nav bar is clicked on, the current form is cleared off the panel and the active form is displayed.
private void tsLblCustomers_Click(object sender, EventArgs e)
{
pnlMain.Controls.Clear();
CustomerReport cr = new CustomerReport();
cr.TopLevel = false;
cr.AutoScroll = true;
cr.BackColor = Color.White;
pnlMain.Controls.Add(cr);
cr.Show();
}
private void tsLblEmployees_Click(object sender, EventArgs e)
{
pnlMain.Controls.Clear();
EmployeeReport emp = new EmployeeReport();
emp.TopLevel = false;
emp.AutoScroll = true;
emp.BackColor = Color.White;
pnlMain.Controls.Add(emp);
emp.Show();
}
private void tsLblVendors_Click(object sender, EventArgs e)
{
pnlMain.Controls.Clear();
VendorReport vend = new VendorReport();
vend.TopLevel = false;
vend.AutoScroll = true;
vend.BackColor = Color.White;
pnlMain.Controls.Add(vend);
vend.Show();
}
private void MainForm_Load(object sender, EventArgs e)
{
WelcomeForm welcome = new WelcomeForm();
welcome.TopLevel = false;
welcome.AutoScroll = true;
welcome.BackColor = Color.White;
pnlMain.Controls.Add(welcome);
welcome.Show();
}

Minimize and Hide Winform on Form Load

I have a Windows Form in a C# program with the FormBorderStyle set to FixedToolWindow.
The window doesn't have the normal control box, but the user can still minimize it from a menu. There is also a setting for the window to start in a minimized state.
When the user clicks the minimize button it called the following function:
private void minimizeWindow()
{
timer1.Enabled = false;
this.WindowState = FormWindowState.Minimized;
this.Hide();
}
The window becomes a small box in the bottom left of the screen, then disappears (from the this.hide call).
When the same function is called from within the Form_Load method (when the setting is to start minimized) it minimizes but does not disappear.
My guess is that because I am hiding the form before reaching the end of Form_Load it is being shown again when it reaches the end of the method. Is there any way to ensure the form hides when it is loaded (it is maximised again from a system tray icon)?
Edit: Included all code from form load
private void Form1_Load(object sender, EventArgs e)
{
this.Left = windowXPos;
this.Top = windowYPos;
sysTrayIcon.MouseDoubleClick += new MouseEventHandler(sysTrayIcon_MouseDoubleClick);
sysTrayIcon.BalloonTipText = "Timers Running";
this.sysTrayIcon.Icon = this.Icon;
sysTrayIcon.Visible = true;
sysTrayIcon.ShowBalloonTip(500);
Start(); //sets up timers
if (startMinimized)
{
minimizeWindow();
}
}
It might be best to change your logic slightly, and instead of showing the form at all, create an instance of it (var foo = new MyForm()) but don't call .Show() so it will never be shown until triggered from your system tray icon.

Resize all the windows of an application

I am creating a Windows app that will have multiple forms in it. Initially, I have set WindowState Maximized for all.
My problem here is that when I minimise one form, size of the other forms stay same. So, if I minimize the main screen go to the next screen, the size of the next screen remains unchanged. All I need to do is change size of all the windows at once.
I tried this:
Mainscreen mainscreen = new Mainscreen();
this.WindowsState = mainscreen.WindowsState;
But I am finding a way to do it for all screens.
A very ugly demo for your reference
private List<Form> Windows { get; set; }
public Form1()
{
InitializeComponent();
this.Text = "Main Window";
this.Windows = new List<Form>();
var defaultSize = new Size(200, 100);
for (var i = 0; i < 3; i++)
{
var form = new Form() { Size = defaultSize, Text = "Resize Me" };
var suppressEvent = false;
form.SizeChanged += (sender, e) =>
{
if (suppressEvent)
return;
suppressEvent = true;
defaultSize = (sender as Form).Size;
foreach (var otherForm in this.Windows)
{
if (otherForm != sender as Form)
otherForm.Size = defaultSize;
}
suppressEvent = false;
};
this.Windows.Add(form);
form.Show();
}
}
If the minimization is the concern and all sub forms launch from a previous form the quickest way would be to have the main form be the owner of the sub form.
If you make a simple project with two forms Form1 and Form2 and add a button onto Form1 that launches Form2 it would look like the following.
private void button1_Click(object sender, EventArgs e)
{
Form2 lForm = new Form2();
lForm.Show(this);
}
Passing "this" (which is reference to Form1) into the constructor of show will make sure that when it minimizes the subform (Form2) will also minimize. You can also change the setting of Form2 and set
lForm.ShowInTaskbar = false;
if you wanted to help make it clear that all of the forms are tied together.
If you are instead talking about having all forms maintain the same size regardless of who started the change and what the size ends up being then it gets a bit trickier and the simplest way would be to make a form manager of some sort that listens to the OnSizeChanged event and updates all forms whenever any form updates. Keep in mind with this that you'll also need to have a test in the form to know whether or not it is the one that started the update otherwise you would get in a sort of infinite loop where Form1 updates causing Form2 to update which then sends out another message which tries to make Form1 update etc...

Saving Location for next form

Alright so I'm doing something with next buttons that open new forms, annoying thing is that new forms pop up somewhere I don't want to on the desktop.
I'm trying to get the new form to spawn on the location of the old form with the code below, unfortunately for whatever reason it's not working at all, they still pop up the same way as before. And yes I have registered the events.
Form1:
System.Drawing.Point LocationPoint = new System.Drawing.Point(200,200);
private void Installer_template_LocationChanged(object sender, EventArgs e)
{
// Save the window location to the installer arts
LocationPoint = this.Location;
}
private void NextButton_Click(object sender, EventArgs e)
{
var NextForm = new Form2(LocationPoint);
NextForm.Show();
this.Hide();
}
Form2
public Form2(System.Drawing.Point LocationPoint)
{
InitializeComponent();
this.Location = LocationPoint;
}
The code is something along those lines
Have you tried setting the StartPosition of the new forms, i.e.
this.StartPosition = FormStartPosition.Manual;
or
this.StartPosition = FormStartPosition.CenterParent;
Alrighty I fixed it, it was a bunch of problems.
Wrong property, gotta use DesktopLocation instead of Location property
Second I had some issues with static member that couldn't be modified or whatever the error is, I just used the settings file to save my location instead
Having that done, it still didn't work because you can't just do this.DesktopLocation = something, you have to use this.SetDesktopLocation(X, Y)
Still didn't work, because it got overwritten by other code when loading the form so you had to use the Shown even of the form and run it in there..

C#.NET MDI bugs when programmatically hiding and showing again a maximized child form and when maximized, child form's icon cannot be changed

Basically I am having two problems with C#.NET MDI. You can download VS2010 solution which reproduces bugs here.
1) When programmatically hiding and showing again a maximized child form, it is not maximized properly again and becomes neither maximized or in normal state.
childForm = new Form();
childForm.Text = "Child Form";
childForm.MdiParent = this;
...
private void showButton_Click(object sender, EventArgs e)
{
childForm.Visible = true;
}
...
private void hideButton_Click(object sender, EventArgs e)
{
childForm.Visible = false;
}
When child form is maximized, then programicaly hidden and shown again, it becomes something like this (please notice the menu bar - child form's control box appears, but child form is not maximized):
At this stage, child form cannot be moved around. However, I found a workaround for that, simply by showing and hiding a dummy child form, which forces the actual child form to become properly maximized. But this makes MDI area to flicker. Tried Invalidate, Refresh, Update methods, but they don't help. Maybe there are other workarounds to overcome this bug and not to make MDI area flicker with dummy child form?
private void workaround1Button_Click(object sender, EventArgs e)
{
dummyForm.Visible = true;
dummyForm.Visible = false;
}
2) When child form is maximized, the icon of the child form is displayed on menu bar. However, if you have to change the icon while the child form is maximized, the icon on the menu bar is not being refreshed (see the image above). I found a workaround for that too, which basically hides and shows menu bar. Icon gets refreshed, but it makes everything below menu bar to flicker. Tried Invalidate, Refresh, Update methods, but they don't help. Is there any other way to make menu bar to refresh the child form's icon?
private void workaround2Button_Click(object sender, EventArgs e)
{
menuStrip.Visible = false;
menuStrip.Visible = true;
}
Also I noticed that when parent form is in normal window state mode (not maximized) and you change the width or height of the form by 1 pixel, child form becomes maximized as it should be and child form's icon on menu bar gets refreshed properly and you don't need other workaround I described above. If I change the size of the form programicaly, form flickers by 1 pixel and I cannot do that, when parent form is maximized. Is there any way how I could invoke the repaint/refresh functionality which is called when you resize a form and which makes child form become maximized properly and the icon on the menu bar refreshed?
There's a bug in the implementation of the internal MdiControlStrip class, the control that displays the icon and the min/max/restore glyphs in the parent window. I haven't characterized it as yet, the code isn't that easy. A classic side effect of the bug is that the glyphs get doubled up, you found some other side-effects. The fix is simple though, delay creating the child windows until after the constructor is completed. Like this:
public MainForm()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e) {
childForm = new Form();
childForm.Text = "Child Form";
childForm.MdiParent = this;
dummyForm = new Form();
dummyForm.MdiParent = this;
dummyForm.WindowState = FormWindowState.Maximized;
base.OnLoad(e);
}
Have you tired using Hide/Show instead of setting visible to true/false?
Try:
private void showButton_Click(object sender, EventArgs e)
{
childForm.Show();
}
private void hideButton_Click(object sender, EventArgs e)
{
childForm.Hide();
}
How about this workaround?
private void showButton_Click(object sender, EventArgs e)
{
childForm.Visible = true;
childForm.WindowState = (FormWindowState)childForm.Tag;
}
private void hideButton_Click(object sender, EventArgs e)
{
childForm.Visible = false;
childForm.Tag = childForm.WindowState;
childForm.WindowState = FormWindowState.Normal;
}
UPDATE
I just gave you the idea how you could do. A better solution using the same idea as above would be a new base form which saves the windows state. See below. Derive your forms from FixedForm instead of Form:
public partial class FixedForm : Form
{
private FormWindowState lastWindowState;
public FixedForm()
{
InitializeComponent();
}
protected override void OnVisibleChanged(EventArgs e)
{
base.OnVisibleChanged(e);
if (Visible)
{
WindowState = lastWindowState;
}
else
{
lastWindowState = WindowState;
WindowState = FormWindowState.Normal;
}
}
}
Found a way how to come around those bugs.
First of all you need to suspend painting for a form and its children. I found a very helpful thread here, which describes how to do it.
After suspending painting, you need call UpdateBounds method of the control and increase ClientRectangle Width or Height by one and then decrease it back to the same value it was before. This invokes layout functionality which makes everything to update/repaint. Last step is to enable painting. Not very nice solution I guess, but it works.
StopDrawing();
UpdateBounds(Location.X, Location.Y, Width, Height, ClientRectangle.Width, ClientRectangle.Height + 1);
UpdateBounds(Location.X, Location.Y, Width, Height, ClientRectangle.Width, ClientRectangle.Height - 1);
StartDrawing();
I find suspending painting very helpful not only for working around those two bugs, but also in general to make GUI work more smoothly. I guess this can help to remove any kind of flickering. However, this solution requires P/Invokes, which should be avoided in general.
Why not just manually reset required icon in menuStrip items, after the creation of the window:
menuStripMain.Items[0].Image = null;

Categories