• 用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实例的引用。这样订阅事件的地方(比如说我们的客户代码中)就可以通过该引用来把新添加的DocumentPaneNewContentAdded事件挂到某个方法上了(当然就是我们的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

     

  • 相关阅读:
    Python之sys & os
    1161
    1142
    P1599 货币
    P1547逆转,然后再见
    P1629八
    P1753HackSon的趣味题
    Problem 2233 ~APTX4869
    1269
    1091. Tmutarakan Exams
  • 原文地址:https://www.cnblogs.com/cuipengfei/p/1688510.html
Copyright © 2020-2023  润新知