You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

431 lines
16 KiB
C#

using System;
using System.Drawing;
using System.Windows.Forms;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Runtime.InteropServices;
namespace Mesnac.Docking
{
partial class DockPanel
{
// This class comes from Jacob Slusser's MdiClientController class:
// http://www.codeproject.com/cs/miscctrl/mdiclientcontroller.asp
private class MdiClientController : NativeWindow, IComponent, IDisposable
{
private bool m_autoScroll = true;
private BorderStyle m_borderStyle = BorderStyle.Fixed3D;
private MdiClient m_mdiClient = null;
private Form m_parentForm = null;
private ISite m_site = null;
public MdiClientController()
{
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
lock (this)
{
if (Site != null && Site.Container != null)
Site.Container.Remove(this);
if (Disposed != null)
Disposed(this, EventArgs.Empty);
}
}
}
public bool AutoScroll
{
get { return m_autoScroll; }
set
{
// By default the MdiClient control scrolls. It can appear though that
// there are no scrollbars by turning them off when the non-client
// area is calculated. I decided to expose this method following
// the .NET vernacular of an AutoScroll property.
m_autoScroll = value;
if (MdiClient != null)
UpdateStyles();
}
}
public BorderStyle BorderStyle
{
set
{
// Error-check the enum.
if (!Enum.IsDefined(typeof(BorderStyle), value))
throw new InvalidEnumArgumentException();
m_borderStyle = value;
if (MdiClient == null)
return;
// This property can actually be visible in design-mode,
// but to keep it consistent with the others,
// prevent this from being show at design-time.
if (Site != null && Site.DesignMode)
return;
// There is no BorderStyle property exposed by the MdiClient class,
// but this can be controlled by Win32 functions. A Win32 ExStyle
// of WS_EX_CLIENTEDGE is equivalent to a Fixed3D border and a
// Style of WS_BORDER is equivalent to a FixedSingle border.
// This code is inspired Jason Dori's article:
// "Adding designable borders to user controls".
// http://www.codeproject.com/cs/miscctrl/CsAddingBorders.asp
// Get styles using Win32 calls
int style = NativeMethods.GetWindowLong(MdiClient.Handle, (int)Win32.GetWindowLongIndex.GWL_STYLE);
int exStyle = NativeMethods.GetWindowLong(MdiClient.Handle, (int)Win32.GetWindowLongIndex.GWL_EXSTYLE);
// Add or remove style flags as necessary.
switch (m_borderStyle)
{
case BorderStyle.Fixed3D:
exStyle |= (int)Win32.WindowExStyles.WS_EX_CLIENTEDGE;
style &= ~((int)Win32.WindowStyles.WS_BORDER);
break;
case BorderStyle.FixedSingle:
exStyle &= ~((int)Win32.WindowExStyles.WS_EX_CLIENTEDGE);
style |= (int)Win32.WindowStyles.WS_BORDER;
break;
case BorderStyle.None:
style &= ~((int)Win32.WindowStyles.WS_BORDER);
exStyle &= ~((int)Win32.WindowExStyles.WS_EX_CLIENTEDGE);
break;
}
// Set the styles using Win32 calls
NativeMethods.SetWindowLong(MdiClient.Handle, (int)Win32.GetWindowLongIndex.GWL_STYLE, style);
NativeMethods.SetWindowLong(MdiClient.Handle, (int)Win32.GetWindowLongIndex.GWL_EXSTYLE, exStyle);
// Cause an update of the non-client area.
UpdateStyles();
}
}
public MdiClient MdiClient
{
get { return m_mdiClient; }
}
[Browsable(false)]
public Form ParentForm
{
get { return m_parentForm; }
set
{
// If the ParentForm has previously been set,
// unwire events connected to the old parent.
if (m_parentForm != null)
{
m_parentForm.HandleCreated -= new EventHandler(ParentFormHandleCreated);
m_parentForm.MdiChildActivate -= new EventHandler(ParentFormMdiChildActivate);
}
m_parentForm = value;
if (m_parentForm == null)
return;
// If the parent form has not been created yet,
// wait to initialize the MDI client until it is.
if (m_parentForm.IsHandleCreated)
{
InitializeMdiClient();
RefreshProperties();
}
else
m_parentForm.HandleCreated += new EventHandler(ParentFormHandleCreated);
m_parentForm.MdiChildActivate += new EventHandler(ParentFormMdiChildActivate);
}
}
public ISite Site
{
get { return m_site; }
set
{
m_site = value;
if (m_site == null)
return;
// If the component is dropped onto a form during design-time,
// set the ParentForm property.
IDesignerHost host = (value.GetService(typeof(IDesignerHost)) as IDesignerHost);
if (host != null)
{
Form parent = host.RootComponent as Form;
if (parent != null)
ParentForm = parent;
}
}
}
public void RenewMdiClient()
{
// Reinitialize the MdiClient and its properties.
InitializeMdiClient();
RefreshProperties();
}
public event EventHandler Disposed;
public event EventHandler HandleAssigned;
public event EventHandler MdiChildActivate;
public event LayoutEventHandler Layout;
protected virtual void OnHandleAssigned(EventArgs e)
{
// Raise the HandleAssigned event.
if (HandleAssigned != null)
HandleAssigned(this, e);
}
protected virtual void OnMdiChildActivate(EventArgs e)
{
// Raise the MdiChildActivate event
if (MdiChildActivate != null)
MdiChildActivate(this, e);
}
protected virtual void OnLayout(LayoutEventArgs e)
{
// Raise the Layout event
if (Layout != null)
Layout(this, e);
}
public event PaintEventHandler Paint;
protected virtual void OnPaint(PaintEventArgs e)
{
// Raise the Paint event.
if (Paint != null)
Paint(this, e);
}
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case (int)Win32.Msgs.WM_NCCALCSIZE:
// If AutoScroll is set to false, hide the scrollbars when the control
// calculates its non-client area.
if (!AutoScroll)
NativeMethods.ShowScrollBar(m.HWnd, (int)Win32.ScrollBars.SB_BOTH, 0 /*false*/);
break;
}
base.WndProc(ref m);
}
private void ParentFormHandleCreated(object sender, EventArgs e)
{
// The form has been created, unwire the event, and initialize the MdiClient.
this.m_parentForm.HandleCreated -= new EventHandler(ParentFormHandleCreated);
InitializeMdiClient();
RefreshProperties();
}
private void ParentFormMdiChildActivate(object sender, EventArgs e)
{
OnMdiChildActivate(e);
}
private void MdiClientLayout(object sender, LayoutEventArgs e)
{
OnLayout(e);
}
private void MdiClientHandleDestroyed(object sender, EventArgs e)
{
// If the MdiClient handle has been released, drop the reference and
// release the handle.
if (m_mdiClient != null)
{
m_mdiClient.HandleDestroyed -= new EventHandler(MdiClientHandleDestroyed);
m_mdiClient = null;
}
ReleaseHandle();
}
private void InitializeMdiClient()
{
// If the mdiClient has previously been set, unwire events connected
// to the old MDI.
if (MdiClient != null)
{
MdiClient.HandleDestroyed -= new EventHandler(MdiClientHandleDestroyed);
MdiClient.Layout -= new LayoutEventHandler(MdiClientLayout);
}
if (ParentForm == null)
return;
// Get the MdiClient from the parent form.
foreach (Control control in ParentForm.Controls)
{
// If the form is an MDI container, it will contain an MdiClient control
// just as it would any other control.
m_mdiClient = control as MdiClient;
if (m_mdiClient == null)
continue;
// Assign the MdiClient Handle to the NativeWindow.
ReleaseHandle();
AssignHandle(MdiClient.Handle);
// Raise the HandleAssigned event.
OnHandleAssigned(EventArgs.Empty);
// Monitor the MdiClient for when its handle is destroyed.
MdiClient.HandleDestroyed += new EventHandler(MdiClientHandleDestroyed);
MdiClient.Layout += new LayoutEventHandler(MdiClientLayout);
break;
}
}
private void RefreshProperties()
{
// Refresh all the properties
BorderStyle = m_borderStyle;
AutoScroll = m_autoScroll;
}
private void UpdateStyles()
{
// To show style changes, the non-client area must be repainted. Using the
// control's Invalidate method does not affect the non-client area.
// Instead use a Win32 call to signal the style has changed.
NativeMethods.SetWindowPos(MdiClient.Handle, IntPtr.Zero, 0, 0, 0, 0,
Win32.FlagsSetWindowPos.SWP_NOACTIVATE |
Win32.FlagsSetWindowPos.SWP_NOMOVE |
Win32.FlagsSetWindowPos.SWP_NOSIZE |
Win32.FlagsSetWindowPos.SWP_NOZORDER |
Win32.FlagsSetWindowPos.SWP_NOOWNERZORDER |
Win32.FlagsSetWindowPos.SWP_FRAMECHANGED);
}
}
private MdiClientController m_mdiClientController = null;
private MdiClientController GetMdiClientController()
{
if (m_mdiClientController == null)
{
m_mdiClientController = new MdiClientController();
m_mdiClientController.HandleAssigned += new EventHandler(MdiClientHandleAssigned);
m_mdiClientController.MdiChildActivate += new EventHandler(ParentFormMdiChildActivate);
m_mdiClientController.Layout += new LayoutEventHandler(MdiClient_Layout);
}
return m_mdiClientController;
}
private void ParentFormMdiChildActivate(object sender, EventArgs e)
{
if (GetMdiClientController().ParentForm == null)
return;
IDockContent content = GetMdiClientController().ParentForm.ActiveMdiChild as IDockContent;
if (content == null)
return;
if (content.DockHandler.DockPanel == this && content.DockHandler.Pane != null)
content.DockHandler.Pane.ActiveContent = content;
}
private bool MdiClientExists
{
get { return GetMdiClientController().MdiClient != null; }
}
private void SetMdiClientBounds(Rectangle bounds)
{
GetMdiClientController().MdiClient.Bounds = bounds;
}
private void SuspendMdiClientLayout()
{
if (GetMdiClientController().MdiClient != null)
GetMdiClientController().MdiClient.PerformLayout();
}
private void ResumeMdiClientLayout(bool perform)
{
if (GetMdiClientController().MdiClient != null)
GetMdiClientController().MdiClient.ResumeLayout(perform);
}
private void PerformMdiClientLayout()
{
if (GetMdiClientController().MdiClient != null)
GetMdiClientController().MdiClient.PerformLayout();
}
// Called when:
// 1. DockPanel.DocumentStyle changed
// 2. DockPanel.Visible changed
// 3. MdiClientController.Handle assigned
private void SetMdiClient()
{
MdiClientController controller = GetMdiClientController();
if (this.DocumentStyle == DocumentStyle.DockingMdi)
{
controller.AutoScroll = false;
controller.BorderStyle = BorderStyle.None;
if (MdiClientExists)
controller.MdiClient.Dock = DockStyle.Fill;
}
else if (DocumentStyle == DocumentStyle.DockingSdi || DocumentStyle == DocumentStyle.DockingWindow)
{
controller.AutoScroll = true;
controller.BorderStyle = BorderStyle.Fixed3D;
if (MdiClientExists)
controller.MdiClient.Dock = DockStyle.Fill;
}
else if (this.DocumentStyle == DocumentStyle.SystemMdi)
{
controller.AutoScroll = true;
controller.BorderStyle = BorderStyle.Fixed3D;
if (controller.MdiClient != null)
{
controller.MdiClient.Dock = DockStyle.None;
controller.MdiClient.Bounds = SystemMdiClientBounds;
}
}
}
internal Rectangle RectangleToMdiClient(Rectangle rect)
{
if (MdiClientExists)
return GetMdiClientController().MdiClient.RectangleToClient(rect);
else
return Rectangle.Empty;
}
}
}