• AvalonDock使用心得


      桌面程序的应用,不可避免的就会用到大量的布局控件,之前的一个项目也想过去做类似于Visual Studio的那种灵活的布局控件,也就是界面上的控件能够实现拖拽放置、隐藏、窗口化等一系列的操作,但由于开发时间以及需求的原因,没有太严格要求这方面功能的实现,也就只能算是想过一下而已,实际用的时候还是固定布局,但是最近接触到新的项目,需要这方面的应用就不得不自己动手查找和做这样的东西了。

      有朋友推荐RadControls里了控件——RadDocking,下载安装RadControls后,发现他里边的控件的确做的很不错,而且Demo也很详细,RadDocking也能满足我的需求,使用也还算方便,但是因为是试用版的,每次程序运行时都会出现相应的提示,尝试找他的最新版的破解版最终也无果,个人又不屑于用很久之前的版本,而且毕竟不是知根知底的东西,用起来也觉得怪怪的,所以还是放弃了使用RadDocking。

      就在我快要放弃寻找,准备有时间自己做的时候(后来发现自己想的有点简单了),让我发现了AvalonDock,看了下它的Demo发现效果也不错,至少看起来能够满足我的应用需求,而且还是开源的,顺便就当研究学习了。大家可以到http://avalondock.codeplex.com/下载和了解更加详细的信息。说了这么多废话赶紧进入正题吧!

      

      虽然有现成的Demo,但第一次接触这类控件还是折腾了不少时间,一点点的摸索它的使用方法!

      一、最基本的布局格式,容器的承载:

    容器布局

      仔细看的话就能发现这里边有一定的层次关系。 

      首先需要一个DockingManager来统筹全局,它能够帮忙管理和处理在其范围内的子级控件的一系列操作——安排载窗格,窗格和处理飞出浮动窗口,以及布局的保存和恢复。感觉好像是只有同一DockingManager下的各个控件才能互相作用,不同DockingManager下的控件是无法跨界操作的。

      再就是DockingManager里放置ResizingPanel,它也是一个容器,用来控制其子控件的布局方式,其Orientation属性类似于StackPanel的同名属性,表示其子级控件是水平或是垂直放置。

      接下来就是两组东西了,它们是一一对应的,DockablePane与DockableContent对应,DocumentPane与 DocumentContent对应,而且都是前者包含后者。DockablePane、DocumentPane都可以也都应该放置到 ResizingPanel,具体的布局方式就看实际应用的需要了,而DockableContent、DocumentContent下包含的就是我们最终想要呈现给用户的功能模块控件了。

      需要指出的是DockablePane和DocumentPane都继承至Pane,DockableContent和entContent都继承至Managedcontent,在后面一些问题的处理上会用的到。

      下面就分别是DockablePane和DocumentPane的呈现形式,从界面上也能看出点不同的哈,具体的一些不同会在下面根据我自己的经验详细讲解到。

          

     

       接下来就是一些列针对布局的处理了。

       二、布局的保存与恢复

      这两部操作其实很简单,因为DockingManager自身就封装好了相应的方法——SaveLayout、RestoreLayout。它们均有不同的重载形式,即可以传入不同的参数,其中以文件名作为参数传入是最方便的一种。

      实际应用中,需要用户登录时列举出已有的布局列表供其选择,根据其选择应用相应的布局,暂时是通过查找应用程序目录下的xml文件来实现的,就是将该目录下所有的xml文件都列举出来,为此写了一个通用的方法,给定目录和查找的文件扩展名—>返回相应的文件列表。

       

    读取路径下的指定扩展名的文件

      程序有个登陆窗口,需要用户选择相应的布局,根据用户的选择应用对应的布局。列表、集合与界面之间都是通过绑定来实现的,下面很多地方都是类似的用法。 这部分倒没什么值得注意的地方,有一点可说的就是要注意区分默认布局和其他布局的处理。

      登陆时的的布局部分

      登陆以后在作了以下处理:

    界面部分 
    初始化布局列表及控件列表

      也是通过绑定集合的方式与界面结合起来。 由于布局列表在其他地方也用得到,还涉及到添加、删除等操作,为了保证界面与数据的实时响应,使用ObservableCollection<>集合来用于绑定。

                    content.StateChanged += new RoutedEventHandler(dokablecontent_StateChanged);
           content.Closed += new EventHandler(content_Closed);
                    content.Closing += new EventHandler<System.ComponentModel.CancelEventArgs>(content_Closing);
                    content.Closed += new EventHandler(content_Closed);
      以上几个事件尤其需要注意,鼠标对界面操作都是通过相应的事件来与列表之间相互响应的。同时空间的显示与隐藏的实现也在这段代码里。

      保存布局时我就采用的是让用户输入布局名称,根据该名称来保存布局。同时向布局列表中添加该项。   

    保存布局

      布局管理中,对已有的布局进行删除操作,删除列表中的项同时删除相应的文件。 

    删除布局

      这样做可能可能不够完善,xml文件的查找就是一个问题,以后考虑通过读取xml文件内容来判断是否是布局文件,暂时还没有想到更好的办法,不知道大家有没有更好的经验呢?!

     四、动态添加控件 

    添加控件

    五、其他

      还有这样一个事件时的注意的,其实我也说不好他的本质是什么,感觉好像就是每次启动新的布局时,如果以有布局存在空缺或已经关闭的情况下就会到达这里,所以在我在这里将缺失的控件给加上。

    代码

    呵呵,一点小小经验,文章也拖了好久才写好,大家见笑啦!

    偷懒了,没有写一个更好的Demo给大家,用了一些自己项目里现成的代码,希望有问题的朋友可以多多交流,也请大家多多指教,赐教我一些更好的方法!

    文章出处:http://www.cnblogs.com/wdysunflower/archive/2010/07/24/1779960.html

    在使用OpenExpressApp框架工作中,我们将开源的AvalonDock控件作为界面布局来应用。

      AvalonDock是在codeplex上的一个开源项目,专门用于WPF的界面布局,可以做成类似visual studio这样的界面,个人感觉是相当不错的,而且简单易用。 像下面这样的界面用AvalonDock很快就能做出来:

      查看原图(大图) 

      查看原图(大图) 

      有兴趣的话,大家可以去codeplex上下载源代码和例子, 相信很快就能学会。但是本文的重点不在这里,我要说的是在使用AvalonDock时遇到的一个问题。先来看下需求吧,其实很简单,我就是想点击一个按钮能弹出泊靠在底部的DockablePane。效果如下:

      点击前:

     

      点击后:

     

      我的代码如下,XAML:

      代码

    双击代码全选
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <Grid>
            <ad:DockingManager x:Name="dockManager">
                <ad:ResizingPanel Orientation="Vertical">
                    <ad:ResizingPanel Orientation="Horizontal">
                        <ad:DocumentPane x:Name="documentsHost">
                            <ad:DocumentContent Title="File1.doc">
                                <RichTextBox/>
                            </ad:DocumentContent>
                            <ad:DocumentContent Title="File2.doc">
                                <Button x:Name="btn1" Click="btn1_Click" Content="click" Width="300" Height="50" ></Button>
                            </ad:DocumentContent>
                        </ad:DocumentPane>
                    </ad:ResizingPanel>
                    <ad:DockablePane ad:ResizingPanel.ResizeHeight="200" x:Name="pane"/>
                </ad:ResizingPanel>
            </ad:DockingManager>
    </Grid>

      对应的CS文件:

      代码

    双击代码全选
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    private void btn1_Click(object sender, RoutedEventArgs e)
    {
          DockableContent dc = new DockableContent();
          TextBox tb = new TextBox();
          dc.Content = tb;
          dc.HideOnClose = true;
          dc.Title = "Test";
          this.pane.Items.Add(dc);
          this.dockManager.Show(dc);
    }

      写完运行,点击按钮,但是却一点儿反应都没有。更奇怪的是,当我拖动窗体的边框时,DockablePane自己却跳出来了。难道说DockablePane信春哥,原地复活么~

      其实玄机就出在Show方法上,打开源代码,发现Show方法的末尾是这样写的:

      代码

    双击代码全选
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    if (content.ActualWidth == 0.0 && (
           dockParent.Anchor == AnchorStyle.Left || dockParent.Anchor == AnchorStyle.Right))
    {
           ResizingPanel.SetResizeWidth(dockParent, new GridLength(200));
           ResizingPanel.SetEffectiveSize(dockParent, new Size(200, 0.0));
    }
    else if (content.ActualWidth == 0.0 && (
            dockParent.Anchor == AnchorStyle.Left || dockParent.Anchor == AnchorStyle.Right))
    {
            ResizingPanel.SetResizeWidth(dockParent, new GridLength(200));
            ResizingPanel.SetEffectiveSize(dockParent, new Size(200, 0.0));
    }

      相信大家一眼就能看出来,if语句中的两个条件完全一样,而且执行的语句块也是一摸一样。问题就出在这里,AnchorStyle枚举总共有5个值 (Top,Bottom,None,Left,Right),我调用的是一个参数的Show方法,默认的AnchorStyle是 AnchorStyle.None,而且我的需求是底部,就算给也应该是AnchorStyle.Bottom。所以说修改如下:

      代码

    双击代码全选
    1
    2
    3
    4
    5
    6
    7
    DockablePane dockParent = content.ContainerPane as DockablePane;
    dockParent.Anchor = desideredAnchor;
    if (content.ActualWidth == 0.0 && (dockParent.Anchor!=AnchorStyle.None))
    {
           ResizingPanel.SetResizeWidth(dockParent, new GridLength(200));
           ResizingPanel.SetEffectiveSize(dockParent, new Size(200, 0.0));
    }

      现在点击按钮,DockablePane就如约而至了。但是其实还是有问题,就是我在调用Show方法的时候就要这么 this.dockManager.Show(dc,DockableContentState.Docked,AnchorStyle.Bottom);

      但是当我改为Top,Left,Right时,期望出现对应的效果,但是最终仍然出现在了底部。而且当我给None的时候,表面上看 DockablePane没有弹出来,但是一旦拖动窗体大小,就又出来了。还有 ResizingPanel.SetEffectiveSize(dockParent, new Size(200, 0.0));似乎没起到作用,我把它注释掉,依然能弹出DockablePane,我再好好琢磨一下,希望能看到本质,这里先把这个问题提出来,我研究完了再来跟大家分享,大家有兴趣的话一起研究下~

  • 相关阅读:
    kendoGrid edit功能
    kendoGrid Event事件
    你不得不看的81条JavaScript编码小技巧,吐血整理,建议收藏
    H265编码视频流媒体播放器EasyPlayer.js支持9宫格视频同屏播放的写法
    EasyNTS 交叉编译海思系统下的可执行程序实现及测试过程
    EasyNTS在Go1.15版本下linux下无法编译的问题优化
    TSINGSEE青犀视频开发Python3行人分析功能运行一段时间后崩溃是什么原因?
    Mysql数据库导入excel和乱码问题
    聊聊5G:5G技术的落地能给视频娱乐、VR直播带来怎样的潜力?
    企业直播的核心点在哪里?未来将如何发展?
  • 原文地址:https://www.cnblogs.com/xwj517537691/p/2730976.html
Copyright © 2020-2023  润新知