用AvalonDock制作WPF多标签浏览器(三)
昨天遇到了一个Bug,如果在浏览器中打开多个标签,并把其中一个标签拖拽到主窗口的一侧来划分出独立的一个区域,然后在新区域中通过点击加号键添加的新标签内不会被添加上WebBrowser。
说得好绕嘴啊,截张图吧:
而且没有加上WebBrowser的标签的标题是new content(我们在AvalonDock中给新标签的默认标题)而不是New Tab(客户代码中重新赋的值)。
OK,问题明了了,是不是新添加的标签的Got_Focus没能够挂到客户代码中的方法上去呢?
的确是这样,当我们把一个标签(DocumentContent)拖拽到一侧从而划分出一个新区域的时候,AvalonDock会创建一个新的DocumentPane来代表这个新区域。
我们浏览器中默认的DocumentPane是在XAML中声明的,声明时其NewContentAdded
事件就挂到了事件响应方法DocumentPane_NewContentAdded上。
而这个新区域中的DocumentPane是在AvalonDock内部的DocumentFloatingWindow类中创建的,其事件自然没有挂上来。
知道了这些,解决方案自然就有了。
在DocumentFloatingWindow中添加如下事件:
public static event EventHandler<NewDocumentPaneAddedByMouseEventArgs> NewDocumentPaneAddedByMouse;
其中用到的事件参数定义如下:
public class NewDocumentPaneAddedByMouseEventArgs : EventArgs
{
public NewDocumentPaneAddedByMouseEventArgs(DocumentPane addedPane)
{
AddedPane = addedPane;
}
public DocumentPane AddedPane
{
get;
private set;
}
}
依然尊规范在DocumentFloatingWindow中定义如下方法来触发事件:
private void OnNewDocumentPaneAddedByMouse(NewDocumentPaneAddedByMouseEventArgs args)
{
if (NewDocumentPaneAddedByMouse != null)
{
NewDocumentPaneAddedByMouse(this, args);
}
}
并在DocumentFloatingWindow中的ClonePane方法(鼠标拖拽时创建新DocumentPane的工作就是在这个方法中做的)中调用该方法来触发事件,修改后的ClonePane方法是这样的:
public override Pane ClonePane()
{
DocumentPane paneToAnchor = new DocumentPane();
OnNewDocumentPaneAddedByMouse(new NewDocumentPaneAddedByMouseEventArgs(paneToAnchor));
ResizingPanel.SetEffectiveSize(paneToAnchor, new Size(Width, Height));
while (HostedPane.Items.Count > 0)
{
paneToAnchor.Items.Add(
HostedPane.RemoveContent(0));
}
return paneToAnchor;
}
我们只关心其中的OnNewDocumentPaneAddedByMouse(new NewDocumentPaneAddedByMouseEventArgs(paneToAnchor)); 这一句就OK了。
好了,现在每当因鼠标拖拽而创建出一个新的DocumentPane时,都有一个事件会被触发,而且其传递的事件参数中还含有对新添加的DocumentPane实例的引用。这样订阅事件的地方(比如说我们的客户代码中)就可以通过该引用来把新添加的DocumentPane的NewContentAdded事件挂到某个方法上了(当然就是我们的DocumentPane_NewContentAdded方法了)。
接下来修改客户代码吧:
在浏览器窗口的构造方法中添加下面一句:
DocumentFloatingWindow.NewDocumentPaneAddedByMouse +=
(object sender, NewDocumentPaneAddedByMouseEventArgs e) =>
{
e.AddedPane.NewContentAdded += DocumentPane_NewContentAdded;
};
用了lambda表达式,有点长,不过的确还只是一句啊。
这样每个通过鼠标拖拽出来的DocumentPane就和我们在XAML中声明的DocumentPane没什么两样了,它们的NewContentAdded 事件都挂到了DocumentPane_NewContentAdded方法上,这个方法做什么的来着?它做的就是给每一个新标签中置入一个新的WebBrowser。
好了,现在再运行一下,之前的问题不见了。
另外,如果你在使用Win7的话,把某个新标签拖拽出窗口,右击,选择Floating
然后就可以把这个拖拽出来的标签Dock到屏幕的一侧了
那个玻璃化的框框好漂亮啊,呵呵。
好了,到现在为止我们的多标签浏览器基本就运转起来了。如果您发现其中隐含的Bug或者不妥之处请不吝赐教哈!
另外,AvalonDock有两套Theme,我们之前的Restyle只修改了DocumentPaneStyles.xaml,要在Win7下看到想要的效果还要对aero.normalcolor.xaml做同样的修改。
好了,Over and out!