Detect doubleClick on mdiContainer without a child (c# winforms)
I've got a Form
which is a mdiContainer
. When the Form hasn't got a child, I want to capture the doubleClick event when a user doubleClicks 开发者_StackOverflow社区the clientArea (same behavior as Photoshop).
But when I set the doubleClick
event, nothing happens.
How can I achieve this?
Not an ideal solution, but you could set IsMDIContainer to false until a child is created. (When false the event fires ok)
Here's an answer that involves a bit of "mucking around" using a Panel and a strategy to hide and show the MDI Application's Main Form's MdiClient object.
When all MDI child windows are closed, the Panel will fill the MDI Client area and handle Mouse events. If you set the Panel's BackColor property to match the default MDI Client Area background color (how to do this is explained below), you can achieve a "seamless" visual transition ... although : consider you might want to make the color vary as a deliberate strategy to let the user know a double-click, or whatever other mouse event you want to handle, is available.
While you can get this working, as shown in this example, I encourage you to think about whether this feature is "really worth it."
I have not evaluated Gareth S.'s reasonable suggestion above to solve this by using toggling the 'IsMdiContainer Property on the Main MDI Form for the simple reason I am afraid that might involve having to re-create complex windowing configurations, and the side-effect of setting 'IsMdiContainer to false on a Form where the 'IsMdiContainer Property is 'true is to remove the MdiClient control from the Form's control collection : I suspect there would be some tricky side-effects to that, but I could be dead wrong.
I'm more comfortable with a strategy that hides and shows the MdiClient object rather than one that removes it as a side effect of setting a property, and which would then require you to re-add it to the controls collection of the Main MDI Form to use it again. You might make another choice.
I'm not going to go into how the MdiClient object is internally handled, but "cut to the chase" and show you how to work around its lack of handling certain mouse events.
Assumptions :
- You have defined a "secondary" Form named 'Form2 which will be used for all child windows of the Main MDI Form.
Code :
Add a Panel to your Main MDI Form : set its DockStyle to 'Fill; set its BackColor to use the System 'AppWorkspace Color for a background to match the user's machine color preferences settings (that's what the MdiClient default BackColor uses). Write event handlers in this Panel for 'DoubleClick or 'MouseDoubleClick, depending on your preferences.
In your Main MDI Form : declare a Form scoped variable to hold a reference to the MdiClient object.
private MdiClient theMdiClient;
Let's assume you have also declared a bunch of your child windows at Form scope level :
Form2 f2 = new Form2(); Form2 f3 = new Form2(); Form2 f4 = new Form2(); Form2 f5 = new Form2();
Main MDI Form Load event : We need to get a reference to the MdiClient object : if you know you have only one control on the Form (the Panel), you can be pretty sure that MainMdiForm.Controls[1] will contain the MdiClient object during the Form Load event, but it's really better practice to iterate to make sure :
Note : we explain the call that sets the reference to the MDI Main Form in each child window (theMdiParent) in section #5 below
private void Form1_Load(object sender, EventArgs e) { // find the MdiClient control and set a reference foreach (Control theControl in this.Controls) { MdiClient testMdiClient = theControl as MdiClient; if (testMdiClient != null) { theMdiClient = testMdiClient; break; } } // hide the panel panel1.Hide(); // set child windows MdiParent to Main MDI Form // set the child windows reference to this Form // show the child windows f2.MdiParent = this; // explained in section #5 below f2.theMDIParent = this; f2.Show(); f3.MdiParent = this; f3.theMDIParent = this; f3.Show(); f4.MdiParent = this; f4.theMDIParent = this; f4.Show(); f5.MdiParent = this; f5.theMDIParent = this; f5.Show(); // set the initialization flag for future use isInitializing = false; }
Now the more interesting aspect of this problem : how do we re-show the Panel when no child windows are visible in the Main MDI Form. First we'll define a public method in the MDI Main Form : we can then assume that if this method is called by a FormClosed event handler in every child window that: if the MdiChildren.Length property of the Main MDI Form is exactly #1 : the last remaining visible child window has just been closed : Note that we then remove the MdiClient object from the controls collection of the Main MDI Form :
public void MDIChildClosed() { if (this.MdiChildren.Length == 1) { this.Controls.Remove(theMdiClient); panel1.Visible = true; } }
We create a public property in Form2 (all child windows being instances of Form2) to hold the reference to the Main MDI Form, which is their MdiParent:
public Form1 theMDIParent { get; set; }
Then we handle the FormClosed event for the child window (Form2) using the reference to the Mdi Parent (Form 1) to call its public 'MdiChildClosed() method :
private void Form2_FormClosed(object sender, FormClosedEventArgs e) { theMDIParent.MDIChildClosed(); }
And in the MdiChildClosed() method of the Main MDI Form (Form1) : as discussed, we remove the MdiClient object from the Main MDI Form's control collection, and make the Panel, which handles mouse events, visible again :
public void MDIChildClosed() { if (this.MdiChildren.Length == 1) { this.Controls.Remove(theMdiClient); panel1.Visible = true; } }
Now, hopefully, you are wondering : how do you bring back the MdiClient object when the end-user (via button, menu, etc.) makes new Mdi Child Windows after all the MDI child windows have been closed, and the Panel is shown again. However you trigger the creation of new mdi child windows, you're going to do something like this in the Main MDI Form (Form1) :
// hide the panel panel1.Hide(); // add the MdiClient back this.Controls.Add(theMdiClient); // example of creating a new child Form Form2 f6 = new Form2(); f6.MdiParent = this; f6.theMDIParent = this; f6.Show();
Summary : a lot of work for, imho, a relatively small payoff. Obviously you could refactor this code in many ways, and do things much more elegantly. I personally feel that MDI type applications are long "out of fashion."
The only possible "spark" that flies out of this exploration, for me, is the idea that you could put all kinds of configuration controls on your Panel (as used here), perhaps have an option to hide all MDI child windows and display the Panel, rather than waiting until all MDI child windows are closed.
精彩评论