在使用DockPanel与ChrominumFx时,当在以下条件下拖动窗体时,会发生ChromiumWebBrowser崩溃的情况,此种情况也会在DockPanel与GeckoFX或CefSharp结合使用时出现。
出现条件:
- 当Form表单初始时以DockState.Document,然后拖动此表单到非DockState.Document模式时,可以是DockState.Left、DockState.Right或其他。
- 当Form表单初始时以非DockState.Document时,然后拖动此表单到DockState.Document模式时
条件总结:即DockState.Document与其他模式切换时,会出现浏览器控件崩溃的情况。
出现此问题原因是DockPanel动态改变了Form表单的MdiParent,严格来说,并不是DockPanel的问题,如果直接使用Winform的MDI窗口模式,只要改变Form表单的MdiParent,也会导致浏览器控件崩溃。
为什么出现这个原因,目前并未深入分析,主要是也不知道从哪里开始分析,因为只是使用GeckoFX、ChrominumFX、CefSharp第三方浏览器控件才会出现此问题,而.NET 自带的WebBrowser没有此问题。
解决办法:
修改DockPanel部分源码,核心思路是在设置MdiParent之前,把浏览器控件从Form表单移除,设置之后,再把浏览器控件加入Form表单。
修改源码地方(修改的DockPanel版本是:2.13):
在DockContentHandler.CS类中 1053行之后,增加如下代码:
private static readonly object MdiParentChangingEvent = new object();
/// <summary>
/// 开始设置MdiParent之前事件
/// </summary>
public event EventHandler MdiParentChanging
{
add { Events.AddHandler(MdiParentChangingEvent, value); }
remove { Events.RemoveHandler(MdiParentChangingEvent, value); }
}
protected virtual void OnMdiParentChanging(EventArgs e)
{
EventHandler handler = (EventHandler)Events[MdiParentChangingEvent];
if (handler != null)
handler(this, e);
} private static readonly object MdiParentChangedEvent = new object();
/// <summary>
/// 设置MdiParent之后的事件
/// </summary>
public event EventHandler MdiParentChanged
{
add { Events.AddHandler(MdiParentChangedEvent, value); }
remove { Events.RemoveHandler(MdiParentChangedEvent, value); }
}
protected virtual void OnMdiParentChanged(EventArgs e)
{
EventHandler handler = (EventHandler)Events[MdiParentChangedEvent];
if (handler != null)
handler(this, e);
}
修改 DockContentHandler.CS类 785行的SetPane方法
private void SetPane(DockPane pane)
{
if (pane != null && pane.DockState == DockState.Document && DockPanel.DocumentStyle == DocumentStyle.DockingMdi)
{
if (Form.Parent is DockPane)
SetParent(null);
if (Form.MdiParent != DockPanel.ParentForm)
{
FlagClipWindow = true;
OnMdiParentChanging(EventArgs.Empty);
// The content form should inherit the font of the dock panel, not the font of
// the dock panel's parent form. However, the content form's font value should
// not be overwritten if it has been explicitly set to a non-default value.
if (PatchController.EnableFontInheritanceFix == true && Form.Font == Control.DefaultFont)
{ Form.MdiParent = DockPanel.ParentForm;
//Form.MdiParent = null;
Form.Font = DockPanel.Font;
}
else
{
Form.MdiParent = DockPanel.ParentForm;
//Form.MdiParent = null;
}
OnMdiParentChanged(EventArgs.Empty);
}
}
else
{
FlagClipWindow = true;
if (Form.MdiParent != null)
{
OnMdiParentChanging(EventArgs.Empty);
Form.MdiParent = null;
OnMdiParentChanged(EventArgs.Empty);
}
if (Form.TopLevel)
Form.TopLevel = false;
SetParent(pane);
}
}
修改DockContent.CS类,在317行以后增加:
private static readonly object MdiParentChangingEvent = new object();
/// <summary>
/// 开始设置MdiParent之前事件
/// </summary>
public event EventHandler MdiParentChanging
{
add { Events.AddHandler(MdiParentChangingEvent, value); }
remove { Events.RemoveHandler(MdiParentChangingEvent, value); }
}
protected virtual void OnMdiParentChanging(EventArgs e)
{
EventHandler handler = (EventHandler)Events[MdiParentChangingEvent];
if (handler != null)
handler(this, e);
} private static readonly object MdiParentChangedEvent = new object();
/// <summary>
/// 设置MdiParent之后的事件
/// </summary>
public event EventHandler MdiParentChanged
{
add { Events.AddHandler(MdiParentChangedEvent, value); }
remove { Events.RemoveHandler(MdiParentChangedEvent, value); }
}
protected virtual void OnMdiParentChanged(EventArgs e)
{
EventHandler handler = (EventHandler)Events[MdiParentChangedEvent];
if (handler != null)
handler(this, e);
} private void DockHandler_MdiParentChanging(object sender, EventArgs e)
{
OnMdiParentChanging(e);
}
private void DockHandler_MdiParentChanged(object sender, EventArgs e)
{
OnMdiParentChanged(e);
}
在 DockContent.CS类 14 行以后增加:
m_dockHandler.MdiParentChanging += new EventHandler(DockHandler_MdiParentChanging);
m_dockHandler.MdiParentChanged += new EventHandler(DockHandler_MdiParentChanged);
最后,在你的Form表单构造函数那里增加:
this.MdiParentChanging += (o, e) => {
this.Controls.Remove(this.MainWebBrowser);
};
this.MdiParentChanged += (o, e) => {
this.Controls.Add(this.MainWebBrowser);
};
至此,可解决浏览器控件崩溃问题。