65.9K
CodeProject 正在变化。 阅读更多。
Home

WPF 文件列表视图和组合框(第二版)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.97/5 (16投票s)

2014 年 4 月 16 日

CPOL

7分钟阅读

viewsIcon

64038

downloadIcon

2668

这是“WPF 文件列表视图和组合框”的替代方案

该项目目前在此维护https://github.com/Dirkster99/fsc(第三版)当前文章在此

简介  

我最近被要求在我的编辑器中添加一个“文件树面板”(https://edi.codeplex.com/discussions/541888),并一直在寻找一个好的解决方案,因为这个组件确实缺失,而且也确实困扰着我。我找到的最佳解决方案是由 Thomas Willwacher 编写的,一如既往,他在这里 CodeProject。我非常喜欢 Thomas 使用的概念,并审查了他的项目以便集成到我的编辑器中,尽管这还未实现,但我已经发现了一些可能难以修复的问题,尤其是在一个由 IoC 驱动的项目中(我接下来希望这样)。

很难正确地写下这些,所以请不要误会我的意思,我非常感谢 Thomas 发布了他的解决方案。因为我甚至不确定自己是否能从一开始就开发出这样一个出色的文件浏览器概念。但我看到了架构问题,并决定着手解决这个问题,而不是推迟。所以,这是我对此解决方案的看法。我在这里发布它,希望它对其他人有用,并且我们可能能够进一步发展它。

背景

此处提出的解决方案是关于一个可以在工具窗口中使用的文件浏览器控件。用户应该能够浏览目录,列出其文件,过滤已列出的文件,并通过双击、拖放和上下文菜单打开文件。拖放和上下文菜单部分在此未作介绍,因为我认为添加这些并不难。此处提出的解决方案只是 Thomas 在他的文章中发布的相同测试应用程序。我只添加了一个目录浏览器控件,并从头开始构建了 MVVM 架构。

使用代码

本文讨论的是下载部分 FileListView_Version2.zip 中的代码。下载部分中的 FileListView_Version2.1.zip 是一个重构版本,目前正在根据我的观察和论坛部分 Leung Yat Chun 的建议进行开发。 

重用所提供解决方案的代码需要您引用 Dll 程序集(FileListView 和 FolderBrowser),并将 MainWindow.xaml 的部分代码复制到您自己的视图实现中。您还需要 MainWindow.xaml.cs 中的代码来创建必要的视图模型。这基本上是您可以在自己的项目中重用此解决方案所需的一切。

关注点

此处提出的解决方案包含 4 个项目

  • FileListView、FileListViewTest 和
  • FolderBrowser、TestFolderBrowser。

FileListView 项目是包含本文重点介绍的文件浏览器控件核心的程序集。FolderBrowser 项目源自另一篇 CodeProject 文章 [2],并在此包含,因为我认为我需要的是最近位置选择而不是最近文件选择。因此,我也对该解决方案进行了重构,并将结果包含在此处。

该解决方案中的“Test”项目包含一个演示应用程序,可以执行以检查其工作原理。本文的其余部分将重点关注 FileListView 项目,但如果您认为我应该更详细地记录 FolderBrowser 部分,请随时提问/要求更多信息。

FileListView 项目中的视图

FileListView 项目主要分为 3 个完全相互独立的视图。

FilterComboBox

FilterComboBox 继承自 ComboBox 控件 [3],并且应该是完全可主题化的,因为我想支持亮色和暗色皮肤。这基本上是您输入过滤器,如:'*.png'、'*.*',或(我已扩展)'*.png|*.jpg|*.jpeg' 的控件。当用户选择过滤器或在组合框的文本部分按下回车键时,此过滤器将应用于文件列表。

<fview:FilterComboBox DataContext="{Binding FolderView.Filters}"
                      ItemsSource="{Binding CurrentItems}"
                      SelectedItem="{Binding SelectedItem, UpdateSourceTrigger=PropertyChanged}"
                      Text="{Binding CurrentFilter, UpdateSourceTrigger=PropertyChanged}"

                      fvbehav:SelectionChangedCommand.ChangedCommand="{Binding SelectionChanged}"
                      VerticalAlignment="Top"
                      HorizontalAlignment="Stretch"
                      Grid.Column="3"
                      Margin="3"
                    /> 

上面的代码显示了如何在 MainWindow 的 Xaml 中实现 FilterComboBox 控件。值得注意的一点是 SelectionChangedCommand 行为 [4],它基本上是一个自定义的 ComboBox 行为,它将自己绑定到组合框的 KeyUpSelectionChanged 事件。当任一事件发生时,该行为会在 FolderComboBoxViewModel 中执行绑定的 SelectionChanged 命令。这反过来执行 SelectionChanged_Executed 方法,该方法评估当前输入的路径是否引用有效目录。如果输入的路径确实存在,该方法会引发 FolderChangedEventArgs 类型的 OnCurrentPathChanged 事件。此事件由下面将讨论的另一个视图模型接收。

FolderComboBox

FolderComboBox 控件是保存用户可以选择作为其探索基础的文件夹列表的组合框。这包括常见的,如桌面、我的文档和驱动器,但也包含最近访问的位置列表。

FolderComboBox 也使用了上面讨论的 SelectionChanged 行为。它与 FilterComboBox 非常相似,除了 2 个附加项

<Setter Property="ItemTemplate">
  <Setter.Value>
    <DataTemplate DataType="{x:Type vm:FSItemVM}">
      <Grid ToolTip="{Binding FullPath}" ToolTipService.IsEnabled="{Binding ShowToolTip}">
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="{Binding Indentation}"/>
          <ColumnDefinition Width="20"/>
          <ColumnDefinition Width="100"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
          <RowDefinition />
        </Grid.RowDefinitions>
        <Image Grid.Row="0" Grid.Column="1" Source="{Binding Path=DisplayIcon}" Width="16" Height="16"/>
        <TextBlock Grid.Row="0" Grid.Column="2" Text="{Binding DisplayName}" />
      </Grid>
    </DataTemplate>
  </Setter.Value>
</Setter>

此 ItemTemplate 显示了组合框下拉部分中显示的项由一个 Image 和一个 TextBlock 组成。ItemTemplate 绑定到 FolderComboBoxViewModel 中的 ObservableCollection<FSItemVM> CurrentItems 集合的 FSItemVM 类型的实例。

<Setter Property="ItemContainerStyle">
  <Setter.Value>
    <Style TargetType="{x:Type ComboBoxItem}" BasedOn="{StaticResource {x:Type ComboBoxItem}}">
      <Style.Triggers>
        <DataTrigger Binding="{Binding}" Value="{x:Null}">
          <Setter Property="IsEnabled" Value="False" />
          <Setter Property="Template">
            <Setter.Value>
              <ControlTemplate TargetType="{x:Type ComboBoxItem}">
                <Separator Width="0" Height="10"/>
              </ControlTemplate>
            </Setter.Value>
          </Setter>
        </DataTrigger>
      </Style.Triggers>
    </Style>
  </Setter.Value>
</Setter>

FolderComboBox 控件中的第二个有趣之处在于 ItemContainerStyle,它包含一个 DataTrigger,当绑定值是 null 时插入一个 Seperator。上面的 Xaml 字面上会将 null 值转换为下拉列表中一个分隔符条目。这个小技巧在下拉列表中插入了一个 Seperator,使我们能够对项目进行分组,从而用户无法单击额外的空间(因为分隔符不可点击)。

FListView

FListView 基本上是一个开箱即用的 ListView,附加了一个行为,该行为将双击转换为 FileListViewViewModel [5] 中绑定的 DoubleClickCommand。

FileListView 项目中的视图模型

此解决方案包含比原始第一版更多的视图模型。基本上,对于上一节中记录的三个控件中的每一个都有一个视图模型。FolderComboBoxViewModel 和 FileListViewModel 使用 FSItemVM 类来管理它们的特定于文件的集合。FolderListViewModel 是解决方案的核心,因为它实例化了其他控件的视图模型,并在它们发出事件时管理它们的事件,例如

  • ……刚刚选择了一个新文件夹
    (FolderComboBoxViewModel 和 FileListViewModel 中的 OnCurrentPathChanged)
  • ……刚刚选择了一个新过滤器(FilterComboBoxViewModel 中的 OnFilterChanged)
  • ……只是想打开一个文件(FileListViewModel 中的 OnFileOpen)

 

结论

 

转换这个项目花了大约 3-4 天的工作,但我认为这是值得的,因为我现在有了更清晰的理解,并且有动力添加其他功能,例如异步查询和加载 FileListView。这可能包括一个显示在 Folder 或 Filter 组合框中的停止按钮,以停止访问慢速设备时可能花费额外时间的进程。

总的来说,通过深入研究别人的代码,我学到了一些新技巧,所以我再次感谢能成为这个社区的一员。现在,我期待着看到社区对此的看法。

致谢

本文中的类图是使用 #Develop (http://www.icsharpcode.net/opensource/sd/) 绘制的。我想感谢原始文章和代码版本以及 Code Project 上 Leung Yat Chun 的建议。

参考文献 

  • [1] WPF 文件列表视图和组合框(第一版),作者:Thomas Willwacher
    https://codeproject.org.cn/Articles/167873/A-WPF-File-ListView-and-ComboBox
  • [2] WPF 文件夹浏览器,作者:Erik Rude
    https://codeproject.org.cn/Articles/352874/WPF-Folder-Browser
  • [3] 继承自无外观的 WPF 控件
    https://codeproject.org.cn/Articles/575645/Inheriting-from-a-Look-Less-WPF-Control
  • [4] 附加行为中的模式
    https://codeproject.org.cn/Articles/422537/Patterns-in-Attached-Behaviours
  • [5] AttachedCommandBehavior V2,又名 ACB
    http://marlongrech.wordpress.com/2008/12/13/attachedcommandbehavior-v2-aka-acb/

历史

  • 2014 年 4 月 16 日 首次创建
  • 2014 年 6 月 2 日 更新第二版 2.1,包含 Metro 设计图标、工具窗口区域的树形浏览器以及更多内容(请参阅 zip 压缩包中的 Readme.txt 文件)- 接下来我将更新文章或进一步开发此版本 :-) 如果我有时间做其中任何一项……
© . All rights reserved.