winform ShowDialog(this) still fail - c#

I am already aware that using ShowDialog() can cause the form to go behind to its parent form. So I look for a solution.
Many says that the solution is to pass the parent form as a parameter to the child form.
Something like this.
using(Form f = new Form1())
{
f.ShowDialog(this);// while the 'this' is the parent form calling
}
but this code still fails.
This is the scenario.
Open the child form showing the dialog, then when the child form window is still active, click show desktop (or press Window+D) then, open other application.
after opening the application minimize it or close it. now after you close or minimize the other application.
Now the child form is already behind the parent form. now you should press alt+tab or click it form the taskbar to work it again properly.
I will appreciate for any help.

Good question. It seems like then the child dialog is visible, and Windows+D is pressed, the parent form ignores the request (or possibly the OS prevents sending a minimize request to the parent form because it has an active modal dialog). Just guessing. The parent form is never sent a minimize message.
You can observe this by using TOOLS -> Spy++ and notice the lack of window messages sent to the parent window when the child dialog is showing and Windows+D is pressed. The messages received are in the orange box:
That means the parent form is never actually minimized. Windows stops painting it, but opening another window turns the painting back on.
So using the WM_ACTIVATEAPP as a reference point, force the parent form to be minimized. This has the side effect that the child dialog is made invisible. Then listen for the SC_RESTORE message, and reshow the child dialog:
public class RestoreForm : Form {
private const int SC_RESTORE = 0xF120;
private const int WM_SYSCOMMAND = 0x0112;
private const int WM_ACTIVATEAPP = 0x1C;
public RestoreForm() {
Button btn1 = new Button { Text = "ShowDialog(...)", AutoSize = true };
btn1.Click += btn1_Click;
Controls.Add(btn1);
}
protected override void WndProc(ref Message m) {
base.WndProc(ref m);
if (f2 != null) {
if (m.Msg == WM_ACTIVATEAPP) {
if (f2.WindowState == FormWindowState.Minimized) {
this.WindowState = FormWindowState.Minimized;
}
}
else if (m.Msg == WM_SYSCOMMAND) {
var w = m.WParam.ToInt32();
if (w == SC_RESTORE) {
f2.WindowState = FormWindowState.Normal;
//f2.Visible = true; // ignores staying on top of previous parent
f2.ShowDialog(this);
}
}
}
}
Form f2 = null;
void btn1_Click(object sender, EventArgs e) {
f2 = new Form { Text = "Child" };
f2.ShowDialog(this);
}
}

My closest workaround to solve this is set ShowInTaskbar and MinimizeBox to false.
Actually I can just disable ShowInTaskbar without disabling the minimize box, but there is no point, allowing the user to minimize the child form but still they cant perform any action on the parent form.

Related

How to properly dock to the right a form to a MDI in a Windows Form application?

I am adding to a MDI a side bar form (not a child) and docking it to the right.
The top of the side bar appears to overlapping the toolbar. When doing a manual resizing (by dragging), the side bar is "magically" looks fine.
Before resizing:
After Resizing:
public partial class MDI : Form
{
private void InitGenealogicalTree()
{
var form = new GenealogicalTreeForm();
form.TopLevel = false;
form.WindowState = FormWindowState.Normal;
form.Dock = DockStyle.Right;
this.Controls.Add(form);
}
}
Note: The ToolStrip was added in design mode.
How can I properly add the side bar form without having it overlapping the toolbar?
A side-bar windows should not be movable and should not be resizeable and should not be maximize-able, so:
Set FormBorderStyle to FixedToolWindow.
Override WndProc of the side-bar window WndProc to prevent move and prevent maximize:
protected override void WndProc(ref Message m)
{
const int WM_SYSCOMMAND = 0x0112;
const int SC_MOVE = 0xf010;
const int SC_MAXIMIZE = 0xf030;
if (m.Msg == WM_SYSCOMMAND)
{
int command = m.WParam.ToInt32() & 0xfff0;
if (command == SC_MOVE || command == SC_MAXIMIZE)
return;
}
base.WndProc(ref m);
}
Also when adding the side-bar, bring it to front. It means first toolbar should be docked, then the side-bar windows will be docked in the remaining area:
this.Controls.Add(sideBar);
sideBar.BringToFront();
Just put a panel in desigenermode where you want to have your sidepanel and display the sidepanel in the panel.
The following codes lets you display the side bar form in the panel:
var form = new GenealogicalTreeForm();
form.TopLevel = false;
panel.Controls.Add(form);
form.Dock = DockStyle.Fill;
this.Controls.Add(form);
form.Show();

How to make an application with no interface?

I'm making a simple CPU Usage monitor. The application is just an icon in the task bar which uses the Microsoft.WindowsAPICodePack library to display the CPU Usage of a task as an icon progress bar.
This application is currently working fine. For added value, I want to prevent the user from opening the application's form, which is blank. Currently I'm using the following code:
/// <summary>
/// Forces this window to remain minimized.
/// </summary>
private void MainForm_SizeChanged(object sender, EventArgs e)
{
if (WindowState != FormWindowState.Minimized)
WindowState = FormWindowState.Minimized;
}
This causes the form to flash on the screen for an instant and shrink back to the task bar. I'd prefer for absolutely nothing to visibly happen when the icon is clicked. Is there a way to achieve this?
Attempt 1
Following deathismyfriend's advice, I tried to hide the form. The WindowsAPICodePack throws an exception:
A valid active Window is needed to update the Taskbar.
Attempt 2
Setting this.Opacity = 0 didn't quite work. Funnily enough, the form is transparent... until you minimize it. Then it appears and shrinks to the task bar.
This worked for me. Trap WM_SYSCOMMAND and suppress SC_RESTORE / SC_MAXIMIZE:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.Opacity = 0; // prevent ALT-TAB preview
this.WindowState = FormWindowState.Minimized;
}
protected override void WndProc(ref Message m)
{
const int WM_SYSCOMMAND = 0x0112;
const int SC_RESTORE = 0xF120;
const int SC_MAXIMIZE = 0xF030;
if ((m.Msg == WM_SYSCOMMAND) && ((int)m.WParam == SC_RESTORE || (int)m.WParam == SC_MAXIMIZE))
{
return;
}
base.WndProc(ref m);
}
}
*Setting Opacity() to 0 (zero) did prevent the Alt-Tab preview window.
You are going against Windows interface standards to do this. That's why it is hard. The system tray is built for this type of application. You still should be able to animate an icon in the system tray to show this sort of information. Here's another question that helps with the system tray:
How can I make a .NET Windows Forms application that only runs in the System Tray?
Still not elegant, but you could set your FormBorderStyle to FormBorderStyle.None to prevent the right-click context menu on the window preview in aero and then move the form off screen:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
Location = new Point(int.MinValue, int.MinValue);
}
Set the opacity to 1 and put the window in an offscreen location. The form will still flash, but will be invisible to the user.

Why the Parent form is responding to short-cut keys of its Child form?

C# WinForms: I have a MDI form and I have defined some short-cut keys for its menus for example "ALT+C" to open the Actions toolbar button. the problem is that if I open this child form inside the parent form but still I click my mouse somewhere inside the Parent form and press "ACLT+C" it is still responding to it and opening "Actions" menu of the child form. How can I prevent this?
Add a flag on your form
bool actionWindow = false
and then when the window opens set actionWindow to true. In your listener check for actionWindow. Then when the actionWindow closes, set the bool back to false.
try: in the child form put e.Handled = true; in the key press event.
There may be a better solution out there, but a quick way would be to test if the form has focus. So in your child event handler, add the following at the top:
if ( this.MdiParent.ActiveControl.Name != this.Name )
{
return;
}
Obviously this isn't preventing the event from firing, just preventing the subsequent code from running.
Edit: If there is no event handler for the menu item, the only other way I can think of to do this is to create handlers for the Enter and Leave events of the child form:
private void ChildForm_Leave( object sender, EventArgs e )
{
menuItem.Enabled = false;
}
private void ChildForm_Enter( object sender, EventArgs e )
{
menuItem.Enabled = true;
}

Activate a form and process button click at the same time?

I'm using Windows Forms in C#.
I have a main form with a couple of toolbars that contain toolStripButtons. After working with another form that contains data, the main form loses focus and clicking on a toolStripButton does not trigger OnClick event: the first click activates the main form, and only the second click actually pushes the button. I need the user to click a button only once to trigger a Click event, any ideas on how to do that? Thanks.
Notes:
I was using MDI and there were no problems clicking on the parent's form buttons. But now the paramount is to have forms freely floating across multiple displays.
The worker forms have the main form as the Owner property, this way they stay on top of the main form.
When I click on the button of an inactive form, none of MouseHover, MouseEnter, MouseDown nor MouseUp fires. It's just main form's Activate event that fires.
There is a treeView (inside a tabControl, inside a splitContainer, inside a panel), on the main form. Its items are selected upon a first mouse click, even if the main form is inactive. I guess not all controls are equal!
What you need to do is create a class that inherits ToolStrip and handles the WndProc. This is one way to do it. There are others.
private class MyToolStrip : ToolStrip
{
private const uint WM_LBUTTONDOWN = 0x201;
private const uint WM_LBUTTONUP = 0x202;
private static bool down = false;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_LBUTTONUP && !down)
{
m.Msg = (int)WM_LBUTTONDOWN;
base.WndProc(ref m);
m.Msg = (int)WM_LBUTTONUP;
}
if (m.Msg == WM_LBUTTONDOWN) down = true;
if (m.Msg == WM_LBUTTONUP) down = false;
base.WndProc(ref m);
}
}
I've also seen this solution:
protected override void WndProc(ref Message m)
{
// WM_MOUSEACTIVATE = 0x21
if (m.Msg == WM_MOUSEACTIVATE && this.CanFocus && !this.Focused)
this.Focus();
base.WndProc(ref m);
}
I ran into this at the last place I worked, I think the solution I came up with worked more like the latter, but I don't have access to the exact code I used.
if u have Form without borders, so this logic was working for you built in :)
form.FormBorderStyle = FormBorderStyle.None

Is it possible to disable animation when minimizing / restoring window?

When I click minimize button in my Windows Forms application, I don't want it to perform the classic Windows minimize animation (window going down to taskbar).
As far as I know, there's no Minimize event, I can just use Resize, but I have no clue how to detect if I clicked minimize button. I tried to use if ( WindowState = FormWindowState.Minimized ) { ... }, but that does the animation anyway and triggers the code after.
Is there any way to detect minimize button click? Is there any way to disable animations or is that triggered by Windows settings?
This works, but it has an unpleasant side-effect on the taskbar button. I can't think of another way, animation isn't even accessible from SystemParametersInfo().
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
protected override void WndProc(ref Message m) {
// Catch WM_SYSCOMMAND, SC_MINIMIZE
if (m.Msg == 0x112 && m.WParam.ToInt32() == 0xf020) {
this.Hide();
this.WindowState = FormWindowState.Minimized;
this.BeginInvoke(new Action(() => this.Show()));
return;
}
base.WndProc(ref m);
}
}
Update: disabling animation on Aero is possible by pinvoking DwmSetWindowAttribute() with the DWMWA_TRANSITIONS_FORCEDISABLED attribute. See this answer.

Categories

Resources