带有可折叠组的拖放式列表启动器
从任务栏启动数量有限的精选程序、文档或文件夹
引言
本文的主要目的是提供 ListLauncher
的下载,这是一个用于启动一些精选程序、文档或文件夹的小工具。
2011年,我写了我的第一个WPF业余程序,ListLauncher
,作为一个小的UI实验。这个工具可以从我的业余网站下载,但由于该网站已经关闭,我决定在CodeProject的这篇文章中提供这个小工具。
在本文的第三段中,我将介绍 ListLauncher
的程序说明。该说明是从我旧网站页面的一些复制粘贴而来。尽管描述有些宣传性质,但该工具相当简单,并且存在其局限性(不支持URL、已知文件夹、程序命令行选项等)。
选择使用工具来组织和启动您最常用程序的决定是相当个人化的。我怀念在Windows 10“开始”菜单的**列表**中手动组织程序的功能,所以现在我使用Classic Shell开始菜单。在W10文件资源管理器中,我们有具有类似功能的快速访问。
在最后一段中,我将简要讨论代码。代码只是一个额外的下载,请注意代码并不是一个好的(MVVM)编程示例。这是我的第一个WPF程序,最初我使用XAML但没有MVVM。
背景
该程序的起源是由于我对通过大小和分组变化来呈现项目的兴趣,结合用户可以发现和记住的(分层)搜索路径。
这种兴趣,结合精选项目(为了收藏效果或宜家“我自己动手”的效果),产生了一些程序,例如这个“1D”ListLauncher
,“2D”桌面圆形启动器,带有标签页和图标,自由放置在圆形上,以组织大量项目,以及PlayMyMusicFolders,一个以前的W8应用程序,其中精选的音乐文件夹以类似于“沉浸式”现代Windows 8.0开始菜单的方式呈现和组织(现在Groove可以很好地播放本地音乐文件夹)。
使用ListLauncher
在Windows中,有多种方法可以组织和快速访问您日常喜爱的程序、文件夹和文档(快捷键、桌面图标、任务栏图标、开始菜单等)。
List Launcher 是一个基本程序,为喜欢额外精选列表来组织和可视化启动他们喜爱的程序、文档或文件夹的用户探索更长的列表。
在下图左侧,我们看到List Launcher附加在任务栏上(白色矩形图标)。单击一次左键,List窗口出现,再单击一次鼠标左键,启动选定的应用程序,打开文档或文件夹,并最小化列表。按“Ctrl”键并单击一个项目,可以在不最小化列表的情况下启动该项目,以便在文件资源管理器中打开多个文件夹。
该列表由可启动的应用程序、文档或文件夹快捷方式组成,并结合可选的分隔符/组标题。分隔符显示为一条蓝色线条,带有一个文本,用于视觉上组织列表。可以通过单击分隔符来折叠/展开组。折叠的组由带点的分隔符表示。通过这种方式,呈现的信息可以受到限制,但可以通过额外的一次鼠标点击获得一些额外信息。
组织列表
- 您总是从处于项目启动模式的空列表开始。
- 通过点击“+”按钮,您将获得一个窗口来添加分隔符、文件和文件夹。请参见下图。如果您愿意,可以在不关闭添加分隔符窗口的情况下,首先输入所有分隔符/组标题。
- 如果列表不为空,您可以将文件、文件夹和驱动器拖放到列表中。
- 要组织列表的顺序,您也可以使用拖放。被拖动的项目将出现在选定放置项目的下方。
- 这两个带2个点的按钮将折叠和展开所有分隔符。
- 当所有分隔符都折叠时,您可以将折叠的组整体拖放,未折叠的项目则作为单独的项目移动。
- 按下“**Delete**”键并单击项目将删除快捷方式。如果单击折叠的分隔符,则只删除分隔符。
- 请注意,该列表收藏夹的意图是相当稳定的,精选项目是一次性完成的。需要一些时间来熟悉并自动在列表中查找项目。
ListLauncher
是用C# (WPF) 为 Windows 7 编写的,用于将其附加到任务栏。跳转列表的长度是有限的。更长的列表需要修改注册表并影响“开始”菜单。ListLauncher
没有这个限制,因为它自己构建列表。标准窗口装饰(关闭按钮等)被移到窗口底部,以使其看起来更酷,并限制从任务栏到关闭或最小化窗口的鼠标移动距离。尽管列表项的大部分是一次性手动选择的,但拖放功能为小修改提供了额外的便利。该程序将其文件夹中的 ListLaucher.ini 和 .old XML文件保存起来。
关于附加代码的简短说明
正如引言中所述,代码只是一个附加下载,请注意该代码并非良好编程的范例。这是我的第一个WPF程序,最初我使用XAML但没有MVVM。
为了使代码更适合本文,我进行了一次额外的迭代,并为 List
数据添加了一个 ViewModel
,但我没有删除任何代码隐藏(模态对话框,拖放),所以它并不是一个很好的 MVVM 示例。
如果您对程序不太满意并希望进行一些小的UI更改,例如使列表中呈现的项目更大,则可以使用代码。对于重大更改(例如带有鼠标滚动的手风琴列表或为可折叠组列表创建更通用的用户控件),请从头开始。
请参阅上图中的项目解决方案,并参阅下面的 IMyListElement
接口代码
public interface IMyListElement
{
BitmapSource Icon { get; set; }
string FriendlyName { get; set; }
string FullName { get; set; }
// We could also make different classes for ExtraHeader and regular short-cuts:
bool IsExtraGroupHeader { get; set; }
bool IsFolded { get; set; }
// Computed from IsFolded and IsExtraGroupHeader
bool IsHidden { get; set; }
}
具体类 MyListElement
专注于 ListLauncher
。FullName
描述了可启动项目的启动路径,FriendlyName
在列表中显示。如果 Icon 的支持字段为 null
,则 Icon 在 getter 中从 FullName
中检索。
我确实选择为额外的组标题/分隔符制作特殊项。我还选择使用 bool IsExtraGroupHeader
而不是使用特殊的子类。属性 IsHidden
是在 getter 中从 IsExtraGroupHeader
和 IsFolded
计算得出的。
MylistHelper.cs 中的主要函数是 Load
、Save
和 MoveWithExtraHeaderOptions( list1, indexFrom, indexTo)
。后一个函数处理列表中带有组的项目的拖放逻辑。在这个 helper 中,我使用 using MyListType = System....ObservableCollection<MyList.MyListElement>
。使用接口 <IMyListElement>
更通用,但似乎我们必须为 XML 序列化做一些额外的工作。
请参见下方的主视图模型接口
public interface IMainVm
{
// Save in setter:
ObservableCollection<mylistelement> MyList { get; set; }
ICommand FoldAll { get; }
ICommand UnFoldAll { get; }
void OnfoldAll(object p);
void OnUnfoldAll(object p);
// directly called in code behind:
void InsertToMyList(int droppedOnIndex, string fullName, string friendlyName = "");
void OnDragDrop(int indexTo, int indexFrom);
void OnDelete(int deleteIndex);
// OnSetSave();
void OnToggleIsFoldedOfHeader(int HeaderIndex);
}
</mylistelement>
请注意,视图/XAML文件中有大量的代码隐藏,因此我们在代码隐藏中可以找到例如对 ((vm.MainVm)DataContext).InsertToMyList(0, fullName, friendlyName)
或 ((vm.MainVm)DataContext).OnDragDrop(removedIdx, targetIdx)
等的调用。
在此实现中,我没有使用 DataTemplates
(用于 Header
、FoldedHeader
等)和 ItemTemplateSelector
。我使用了一个标准列表,其中元素通过绑定到 MyListElement
属性(例如 IsHidden
、IsExtraGroupHeader
、IsFolded
等)来控制可见性。初步印象,请参见下面的伪 XAML。
请注意,为了在折叠时使列表项完全不可见,我们使用了列表项的样式,否则该项仍以几个像素的高度可见,这会增加折叠组的高度。
< ListBox x:Name="myListBox1" ....
ItemsSource="{Binding MyList}"
ScrollViewer.HorizontalScrollBarVisibility="Hidden"
>
<!--Using style to control visibility ListBoxItem, otherwise still visible height-->
<ListBox.Resources>
<Style TargetType="ListBoxItem">
<Setter Property="Visibility"
Value="{Binding IsHidden, Converter={StaticResource Bool2NotVis}}" />
<Setter Property="Focusable" Value="False"/>
....
</Style>
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type mylist:MyListElement}">
<Grid ToolTip="{Binding Path=FullName}" >
<StackPanel .... Orientation="Horizontal" Margin="-2"
Visibility="{Binding IsExtraGroupHeader, Converter={StaticResource Bool2NotVis}}"
>
<Image .... Source = "{Binding Icon}" />
<TextBlock ... Text="{Binding Path=FriendlyName}" />
</StackPanel>
<DockPanel
Visibility="{Binding IsExtraGroupHeader, Converter={StaticResource Bool2Vis}}">
<Rectangle ... Stroke="SteelBlue"/>
<TextBlock ... Foreground="SteelBlue" Text="{Binding Path=FriendlyName}" />
<StackPanel Orientation="Horizontal" ...
Visibility="{Binding Path=IsFolded, Converter={StaticResource Bool2Vis} }"
>
<Ellipse Fill="SteelBlue" ... />
<Ellipse Fill="SteelBlue" ... />
</StackPanel>
<Rectangle .... Stroke="SteelBlue" />
</DockPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
讨论
尽管这更像一个技巧/提示而非一篇真正的文章,但我选择通过一篇文章来让这个简单的实用工具更广泛地可用。如果您喜欢,请尽情享受。