Figure 0. MVVM Tabbed File Explorer. Group of Folder Tabs can be
opened with one click. Program works only for Windows7.
Table of Contents
- Introduction
- Background
- A short note on attached properties
- A short note on Design and Implementation Process
- Model: Adding FolderPlane, FolderPlaneItem, SavedFolderTabsItem
- ViewModel
- Properties
- Example setter property: SelectedPath
- List of ICommands
- View
- MainViewWindow
- FolderPlaneView
- TabsFolderPlanesView
- SavedFolderTabsView
- FileManagementButtonsView
- What to do for a more mature File Explorer
- Points of interest
- License
- History
Introduction
This is the second article in a series of two. In my first article
Playing with a MVVM Tabbed TreeView for a File Explorer, a requisite for
this article, I described a simple Tabbed TreeView, in this second article I will
add a Tabbed FolderPlane. File Management is provisory. The resulting program can be used as prototype to test how Tabs can be used in a File Explorer for certain tasks. This sample shows in a global way one advantage of MVVM, the seperation of concerns, in a deskop application with some interaction going on.
My main purpose is not to write a fully functional File Explorer but to learn a
little bit more about WPF (I read some books but I am still in the copy/paste phase)
and have my first hands-on MVVM programming experience.
The resulting program can be used as a prototype to get a first impression how Tabs
can be used in a File Explorer and how useful they are.
In the first article I described and showed in some detail the application of basic
MVVM techniques as I understand them as a beginner. Here we show the advantages
of MVVM by describing in a more global way a desktop application with a little bit
more interaction going on. The description of a little bit larger application using
standard techniques is not so fundamental and a little lengthy. It is mainly of
interest as a global example of MVVM or for those who have an interest in the application
itself.
The resulting program has many limitations (W7 only, very provisional File Management,
no drag and drop, Context Menu, etc. etc.) Despite the limitations some topics
might be of interest:
- Short discussion about the File Explorer tasks we want to experiment with.
- A global example of a MVVM desktop application with some interaction going on.
- Only basic MVVM techniques and additional some attached properties and Popups.
- Tabbed FolderPlanes.
- Common Folder Up and Close selected tab button in centre of the Window.
- All tabs can be saved/loaded as a group using named buttons.
- Buttons for provisional (no background process, no feedback) File Management.
- Copy a folder with date added.
- No external DLL's.
Background
First we will have a few words over the File Explorer in general, and the tasks
we want to experiment with in our prototype. In the next section we tell a little
bit about attached properties. For more action, skip right to the Model.
An important question is what is THE ultimate optimal File Explorer. A general File
Explorer must satisfy all users. The best specific File Explorer depends on the
user, his/her experience and preferences and the current task at hand. Given the
importance of the File Explorer for some tasks, it could be thinkable to have several
File Explorers for different audiences/tasks. As a matter of fact there are quite
a few general File Explorers, that differ in functionality and preferences, see
for example wikipedia
and
here.
The Windows 7 File Explorer is very mature and polished and contributes for me to
the UI experience of Windows 7. See for some first design considerations for its
W8 successor
here. As always the capabilities of a File Explorer are important, but users
must also find and learn the patterns how to use those capabilities. The Windows
7 File Explorer is excellent and we don't want to replace it. I noticed some minor
possible improvements for me in some scenario's that I wanted to investigate and
experiment with:
- I noticed a pattern in my use of the File Explorer. Some tasks (2-4) require a number
of fixed folders combined with one or two varying folders. I want to open a group
of all 2-5 tabs for a task at once and copy/move between these.
- If groups are expanded in the Navigation Tree you have to implode the tree or scroll
between groups in the tree. For that reason I wanted to experience how well tabbed
Navigation Trees work.
- I sometimes make a copy of a single folder and add a date.
- Working with 2 Folder Planes for copy and move, like the DOS
Norton Commander. Is somewhat less relevant if tabs are available.
Many articles on coding File Explorers have been written (as a quick Google search will show), but I will
just give three links. The first one focusses on the design of a MVVM File Explorer,
the last two are recently updated Code Project articles of functional File Explorers
(my respect for that).
We will use only basic MVVM techniques. MVVM (Model-View-ViewModel) is a design
pattern for writing WPF programs when separation of concern and unit testing come
into play, a classic article is here "WPF
Apps With The Model-View-ViewModel Design Pattern" by Josh Smith. See
here for a simple overview:
Silverlight View Model Style: An (Overly) Simplified Explanation.
I refer to my first
article where I presented some code snippets of INotifyPropertyChanged
properties, ObservableCollections
and ICommands
and their
bindings in XAML. This article will be less detailed and I only list properties
and commands in the ViewModel.
A Short Note on Attached Properties
In this article I also will use some custom
Attached Properties. Attached properties can be used to the extend WPF classes
that don't have the (MVVM) support required or expected.
Many WPF classes are derived from the
DependencyObject Class that provides hosting support of
dependency properties and
attached properties. They can be specified in XAML and in for example
<Button Height="20" Grid.Row="4"/>
Height
is a dependency
property and Row
is an attached property defined in the Grid
class, hosted by an instance of the Button
class.
It is possible to create your own custom attached properties (or just Google to
find one that solves a common problem). In defining an attached property we can
specify in the RegisterAttached
method the Property Changed Callback
function.
From the parameters of the Callback function we have access to the instance of the
hosting class attached to (target object) and the old and new value of the property.
We can invoke methods, set properties, test the class of the target, retrieve its
datacontext, on attach we can hook to events of the target and on detach unhook
these events. In this way we have a powerful method to extend the behaviour of WPF
classes and the attached properties can be added in XAML to all classes supported.
Attached properties can be used for example to bind events to commands and in Drag
and Drop frameworks (binding to all relevant drag and drop events and executing
at some places code specified by the user). Some links related to the use of attached
properties and attached properties we will use :
Microsoft Expression Blend is, if applicable, the preferred alternative. Use for
example Interaction.Triggers + EventTrigger to bind commands to events. However external
DLL's (Microsoft.Expression.Interactions
, System.Windows.Interactivity
from the
Microsoft Blend SDK) are needed. See also
WPF : Blend 3 Interactions / Behaviours by Sacha Barber or
Behaviors and Triggers in Silverlight by Pencho Popadiyn.
A Short Note on Design and Implementation Process
My former expertise is mainly the design and optimalisation of scientific algorithms
and I have not much of a formal IT background. I started with a global idea of how
the application should look like, see the figure
above. I only wanted to add a tabbed FolderPlane and to save/load group of Tabs
but at the last moment I decided to add some very provisory File Management using
buttons (Take Snapshot, Copy, Move, New Folder, Rename, Delete etc.).
Starting point of the design is the figure and from there our classes for the Model
(NavTreeItem
, FolderPlane
, FolderPlaneItem
)
and the ModelView. A more usual approach is to start from System classes (ShellItems,
Drives, Folders, Directories etc.). We could say that our design takes more the
viewpoint of the sketched figure/view. The chosen approach seems to lead to an initially
simpler design however extra conversions are needed to acces all items (Libraries,
Favorites etc., did not study Shell) and extra conversions could be needed on drag/drop
from/to other applications. We could incoperate in our classes (links to) system
classes.
Although we describe in the article the application in sequential sections Model,
ViewModel and View to emphasise the separation of concerns in MVVM there are smaller
and larger iterations and it is smart to have a.s.a.p. some feedback using testing
or visual presentation of parts of the application.
I used an incremental and iterative approach. Complexity is incremented by adding
new functionality at several scales. Start with one Navigation Tree, add Tabbed
Navigation Trees, one FolderPlane, Tabbed FolderPlanes, etc. Smaller iterations
are add some new functionality, make it to work, test a little bit by clicking (very
light TDD) and next a refactoring step. Because of the separation of concern and
stepwise increasing functionality this works well but in retrorespect the design
of the setting of SelectedPath
and SelectedFolderPlane
would have benefit from a more explicit design beforehand instead of fixing some
scenario's.
As a WPF beginner it takes some time to select the XAML you want to use, and its
takes some time to handle situations where things go not as you expect. Examples
are SelectedItem(s) that are a read-only property you can't bind to, an already
selected item does not fire again, there is no command for double clicking on a
datagrid row, selected item not into view, the selected items of a datagrid seems
to get messed on dragging etc. Luckily Google is your best friend, there are a lot
of solutions around in the community and most of the time you only have to select
the first working or, if there is time left, the best solution.
I will use for this prototype just the standard basic MVVM techniques as I understand
them as a beginner. I will not use common practices as external (Blend) DLL's
or a MVVM framework.
I used one Main View Model (not refactored yet) and to organize
the XAML I moved XAML code to "User Controls", that still need the classes from
the View Model. See figure below for the structure of the project.
Model: Adding FolderPlane, FolderPlaneItem, SavedFolderTabsItem
The class NavTreeItem
is discussed in my former
article. Here we add 3 new classes: FolderPlane
, FolderPlaneItem
and SavedFolderTabsItem
. See the code below for the interface of the
FolderPlane
class and the FolderPlaneItem
class.
public interface IFolderPlane
{
string FullPathName { get; set; }
string FriendlyName { get; set; }
void SetFolderPlane(string path, bool clear = false);
void RefreshFolderPlane();
ObservableCollection<FolderplaneItem> FolderPlaneItems { get; set; }
}
public class FolderPlaneItem
{
public String FullName { get; set; }
public String Name { get; set; }
public String Ext { get; set; }
public String Date { get; set; }
public long Size { get; set; }
public BitmapSource MyIcon { get; set; }
}
We only plan to offer a "Details" list option in the View of the Folder Plane. To
offer more FolderPlane view options some extensions are needed in Model (add to
FolderPlane
a property ViewOption
, have one class FolderPlaneItem
and derived classes like FolderPlaneDetailsItem
), ViewModel (add a
Property ViewFolderPlaneOption
) and View (New DataTemplates).
For the
SavedFolderTabsItem
class see code below. This class will be
used to open a group of Tabs of Folder Planes using a click on a named button. Each
item represents a group with a
FriendlyName
to depict its name and
a
Collection
of
TabFullPathName
for the associated
FolderPlanes
.
Save and Load for
ObservableCollection<SavedFolderTabsItem>
use
the
XmlSerializer
class.
public class SavedFolderTabsItem
{
public string FriendlyName { get; set; }
public Collection<string> TabFullPathName { get; set; }
}
ViewModel
Properties
We will now discuss MainVm
. The class in split in two files (properties
and commands), but it should be refactored in smaller View Models. We will now discuss
all properties in MainVm
, see pseudo code below.
TabbedNavTrees
is discussed in our first article, and when an item
of the tree is clicked the SelectedPath
will be set.
- Next we have properties
SelectedFolderPlane
and FolderPlanes
.
They will be bound in the View to FolderPlaneView
and TabsFolderPlanesView
.
SavedFolderTabs
and SelectedIndexSavedFolderTabs
are used
to manage groups of Tabs. They will be bound in the view to SavedFolderTabsView
.
The setter of the SelectedIndexSavedFolderTabs
will update the FolderPlanes.
- The
ShaderOpacity
property will be bound to the Opacity of the main
grid.
PopUp1IsOpen
will adapt ShaderOpacity
in its setter. It
will be bound in the View to a Popup so when PopUp1IsOpen
is set the
Popup will be opened, and the opacity of the Main grid will be dimmed.
- Finally we keep track of the
SelectedFolderItems
, SelectedFolderItem
and SnappedSelectedItems
for FileManagement. They are set in the commands.
Note that if we want a File Explorer with two FolderPlanes it should be possible
with some work to extend the properties with another SelectedPath2
,
SelectedFolderPlane2
, FolderPlanes2
and a bool
IsFolderPlane1Selected
.
public partial class MainVm : ViewModelBase
{
public TabbedNavTreesVm TabbedNavTrees { get; set;}
public string SelectedPath
public FolderPlane SelectedFolderPlane
public ObservableCollection<FolderPlane> FolderPlanes
public ObservableCollection<SavedFolderTabsItem> SavedFolderTabs
public int SelectedIndexSavedFolderTabs
public double ShaderOpacity
public bool Popup1IsOpen; Popup2IsOpen; Popup3IsOpen
public List<String> SelectedFolderItems
public List<String> SnappedSelectedItems
public String SelectedFolderItem
}
I want to empathise here the advantage of the separation of concerns in MVVM. Although
the code of MainVm
is rather lengthy and has a lot of repetitive code,
it is rather compact if we look to the number of properties. These properties are
not located at all kinds of places in code behind and we can add functionality in
the setters of the properties.
Example Setter Property: SelectedPath
SelectedPath
is set in several commands like SelectedPathFromTreeCommand
,
FolderPlaneItemDoubleClickCommand
, CloseTabCommand
and
FolderUpCommand
. We will now discuss the setter of SelectedPath
,
that contains also the logic (Design Choices) to set the SelectedFolderPlane
.
The setter sets, after resolving shortcuts, SelectedPath
if the value is an empty
string or points to an existing item. In case of an existing item it sets also the
SelectedFolderPlane
. It checks if the path is already in FolderPlanes
to prevent doublures, adds a new Tab or replaces the current SelectedFolderPlane
.
See code below.
public string SelectedPath
{ .....
string testValue = FolderPlaneUtils.ResolveIfShortCut(value);
.....
if (!SetProperty(ref selectedPath, testValue, "SelectedPath")) return;
int indexInPlanes = GetIndexFolderPlanes(selectedPath);
if (indexInPlanes != -1)
{
SelectedFolderPlane = FolderPlanes[indexInPlanes]; .... return;
}
FolderPlane newPlane = new FolderPlane();
newPlane.SetFolderPlane(selectedPath);
if (UseCurrentPlane)
{
UseCurrentPlane = false;
indexInPlanes = GetIndexFolderPlanes(SelectedFolderPlane.FullName);
if (indexInPlanes != -1) {FolderPlanes[indexInPlanes] = newPlane;} else FolderPlanes.Add(newPlane);
}
else
{
FolderPlanes.Add(newPlane);
}
SelectedFolderPlane = newPlane;
...
List of ICommands
To be complete we just give a list of ICommands
, see pseudocode below.
These commands manipulate the properties in the ViewModel and will be bound in the
View. For many commands the canExecute is specified. Buttons that bind to these
commands are only enabled when canExecute returns true. We will give a short global
informal description of some commands to give an impression.
SelectedPathFromTreeCommand
sets the SelectedPath
and
is called when a Tree Item is clicked.
FolderPlaneItemDoubleClickCommand
test if the item clicked is a Folder.
If so it sets the SelectedPath
to that Folder. Otherwise it launches
the item. It is called when a row of the datagrid of the folderplane is double-clicked.
CloseTabCommand
and FolderUpCommand
set the SelectedPath
.
ToggleOpenPopupCommands
are called when some buttons are pressed. They
toggle a PopupIsOpen
property.
SelectedItemsChangedCommand
is called when the SelectedItems of the
datagrid are changed.
- Some commands for File Management. Buttons in the
FileManagementButtonsView
will bind to these commands.
public partial class MainVm
{
public ICommand SelectedPathFromTreeCommand
public ICommand FolderPlaneItemDoubleClickCommand
public ICommand CloseTabCommand, FolderUpCommand
public ICommand ToggleOpenPopup1Command, ToggleOpenPopup2Command, ToggleOpenPopup3Command
public ICommand AddSavedTabsCommand, DeleteSavedTabsCommand, CloseAllFolderTabsCommand
public ICommand SelectedItemsChangedCommand
public ICommand SnapShotSelectedCommand
public ICommand CopySnapShotCommand, MoveSnapShotCommand, CopySnapShotAddDateCommand
public ICommand NewFolderCommand, RenameCommand, DeleteSelectedCommand
public ICommand RefreshFolderPlanesCommand
}
Note that MainVm
contains also some supporting procedures for minimal
file management. However these procedures are very provisory. 1) They give no user
feedback and 2) They are not implemented in a background process, so during copying
very large files the UI hangs. I have not examined yet if something like the C#
5.0/ NET 4.5
Async can help.
View
MainViewWindow
In the View we specify in XAML how to present the data and bind all the relevant
properties (ObservableCollection
, INotifyPropertyChanged
and ICommand
) from the ViewModel. I use "User Controls" just for organizing
the XAML code. First XAML code is developed as part of the MainViewWindow, and after
testing I refactor the XAML code by moving it to a "UserControl" that still requires
the specific ViewModel/DataContext properties they can bind to. See code below for
some snippets of the MainViewWindow. The MainVM is set as Datacontext and all its
(sub) properties will be matched in databindings of the "User Controls":
TabbedNavTreesView
to select a TreeItem.
FolderPlaneView
to show FolderPlaneItems, on double-click change Selected
Folder or launch the item.
TabsFolderPlanesView
to select a SelectedFolderPlane from the open
Tabs, Close and FolderUp current Tab button.
SavedFolderTabsView
to open all Folder Tabs in a group from a named
button, close all Folder Tabs, Delete or Save a named button for all current Tabs.
FileManagementButtonsView
, for buttons Take SnapShot, Copy SnapShot,
Move, Delete Selected etc.
<Window.DataContext>
<vm:MainVm x:Name="MyMainVm"/>
</Window.DataContext>
...
<Grid ... Opacity="{Binding ShaderOpacity}" >
...
<TextBlock Text="{Binding SelectedPath}" ... />
...
<vw:SavedFolderTabsView />
...
<vw:TabbedNavTreesView DataContext="{Binding TabbedNavTrees}"/>
...
<vw:TabsFolderPlanesView/>
...
<vw:FolderPlaneView/>
...
<vw:FileManagementButtonsView/>
...
FolderPlaneView
See for some snippets of the FolderPlaneView
code below, it consists
of a Datagrid. We see that the ItemsSource
binds to the SelectedFolderPlane.FolderPlaneItems
,
the DataGridColumns
bind to the properties (MyIcon,Name etc.) of the
FoderPlaneItem
class.
The datagrid has no standard command for a double click on a Row. The
DoubleClickCommand
is an attached property as discussed before.
It hooks to a DataGrid.MouseDoubleClick
. On Double Click of a DataGrid
Row the FolderPlaneItemDoubleClickCommand
from the MainVm
is called with as parameter the CurrentItem
. This Command launches
an application or in case of a folder it sets the SelectedPath
.
The SelectedItems
of the DataGrid is a read-only property and binding
with an property from the MainVm
is not direct possible. The
CommandExecuter provides some attached properties and it takes care that
on a SelectionChanged
event the SelectedItemsChangedCommand
is called with parameter SelectedItems
. The command updates property
MainVm.SelectedItems
that will be used in the provisory FileManagement
commands.
....
<DataGrid
ItemsSource="{Binding SelectedFolderPlane.FolderPlaneItems}"
SelectionMode="Extended" SelectionUnit="FullRow"
vw:DataGridDoubleClick.DoubleClickCommand="{Binding FolderPlaneItemDoubleClickCommand}"
....
mvvm:CommandExecuter.OnEvent="SelectionChanged"
mvvm:CommandExecuter.Command="{Binding SelectedItemsChangedCommand}"
mvvm:CommandExecuter.CommandParameter="{Binding Path=SelectedItems,ElementName=dataGrid1}" >
<DataGrid.Columns>
<DataGridTemplateColumn Width="SizeToHeader" Header=" Ico " IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Width="16" Height="16" Source="{Binding MyIcon, Mode=OneTime}"/>
.........
</DataGridTemplateColumn>
<DataGridTextColumn Width="*" Binding="{Binding Name, Mode=OneTime}" Header=" Name "/>
<DataGridTextColumn Width="SizeToHeader" Binding="{Binding Ext, Mode=OneTime}" Header=" Extension "/>
..........
TabsFolderPlanesView
The TabsFolderPlanesView presents the FolderPlanes and the SelectedFolderPlane.
See figure below. From left to right we see:
- Two buttons, Close (Red) and FolderUp (Yellow) selected tab
- A number of Tabs/FolderPlanes and the last one is selected. Another Folder Tab can
be selected by clicking on that tab.
- A
dropdown button to select Folder Tabs from a list, as in Visual Studio.
The Folder Tabs can be organized by drag and drop. (Note that we can open new Folder
Tabs by clicking on a TreeItem or we can open a group of tabs in the SavedFolderTabs
using a saved named button). The Scrollbar is a little
adapted so that optionally only two small buttons appear on the right.
Here the Close and FolderUp selected tab buttons are on a fixed position in the
centre of the window to create a "hotzone" for moving up and down (by
clicking FoldersPlaneItems) the tree and to save space in the Folder Tabs. Normally
close buttons are placed on each Tab. Note also that for longer foldernames we try
to replace the spaces with newlines to limit the witdh of the Tabs (See last selected
Folder Tab "Program Files", split in 2 lines)
The Folder Tabs are formed by a ListBox, see my first article. The ListBox is derived
from class ItemsControl
and properties can be set for the Control itself
and for its items/children. See code below.
- We see that in the ListBox there are data bindings to
FolderPlanes
,
SelectedFolderPlane
and FriendlyName
(using the DataTemplate).
ButtonOnlyScrollViewer
is for the adapted ScrollViewer.
FolderPlaneTabs
takes care to present the selected/not selected Folder
Tabs.
FolderPlanesHeaders_SelectionChanged
is my only code behind (using
lb.ScrollIntoView(..)
and lb.UpdateLayout()
) to see that
the selected FolderTab comes into view when selected using the dropdown list.
ItemsPanel
is changed to a horizontal StackPanel
I wanted to organize the order of the Tabs (ListBox) by drag and drop within these
lists. As an exersize I wrote my first attached property with a very basic Drag
and Drop without visual feedback. Due to the vw:DnDSortOneListBox.Attach1="True"
attached property the Tabs (ListItems) can be dragged and dropped within the list.
However this is an ad hoc solution for a specific case when only ListBoxes are involved
and we should introduce a MVVM drag and drop framework for the whole application.
<DataTemplate x:Key="FolderPlaneHeader" DataType="{x:Type mdl:FolderPlane}">
<TextBlock ... Text="{Binding FriendlyName}" ToolTip="{Binding FullPathName}"/>
</DataTemplate>
... scrolviewer stuff
... style FolderPlaneTabs
... CloseCurrentTab, FolderUp buttons
<ListBox
ItemsSource="{Binding FolderPlanes}"
SelectedItem="{Binding SelectedFolderPlane, Mode=TwoWay}"
ItemTemplate="{StaticResource FolderPlaneHeader}"
IsSynchronizedWithCurrentItem="True"
Template="{StaticResource ButtonOnlyScrollViewer}"
ItemContainerStyle="{StaticResource FolderPlaneTabs}"
SelectionChanged="FolderPlanesHeaders_SelectionChanged"
vw:DnDSortOneListBox.Attach1="True">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ListBox>
The right Button is a dropdown button that shows a list of Tabs to select one. See
code below. I use a little hack with the Menu and Combobox to get a dropdownlist
with not too much XAML code. However Width, MaxWidth and Margin are not so robustly
tweaked to get a somewhat acceptable look.
<Button Width="26" Height="20" Grid.Column="2"
Focusable="False" ToolTip="List tabs and select">
<!---->
<Menu MaxWidth="20" Background="{StaticResource FolderTabs}">
<ComboBox
Margin="-6,-2,-6,-2"
DisplayMemberPath="FullPathName"
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding FolderPlanes}"
SelectedItem="{Binding Path=SelectedFolderPlane, Mode=TwoWay}"/>
</Menu>
</Button>
...
SavedFolderTabsView
The SavedFolderTabsView presents the possibility to open a saved named group of
FolderPlanes Tabs with one click. See figure below, from left to right we see:
- "Temp" and "Fe project" are named "Buttons" to open a group of Folder Tabs.
- Close all Button, closes all open Folder Tabs.
- Delete Button, delete a named "Button", opens a popup.
- Save Button, save all current Folder Tabs under a named "button", opens a popup
The named "Buttons" can be sorted by drag and drop, when another named "Button"
is selected the new order is saved. Note that the support to update a named group
is provisory and you have to improvise: open a group, reorganize the Tabbed FolderPlanes
and save the new group. Note that it is possible by using XAML to replace the named
buttons by for example small colored circles that expand on hover.
The named "Buttons" are again a ListBox that uses a horizontal StackPanel as its
ItemsPanel. Its ItemsSource
binds to the MainVm.SavedFolderTabs
property and SelectedIndex
binds to MainVm.SelectedIndexSavedFolderTabs
.
The ItemTemplate / DataTemplate binds to the FriendlyName
of the
SavedFolderTabsItem
.
In this simple MVVM example we use Popups instead of Modal Windows to keep it simple.
Modal Windows are supported in MVVM frameworks or see
here (not studied yet). See figure above and the code below for the Save
button. When the button is clicked the ToggleOpenPopup2Command
is called,
Popup2IsOpen
is set, Opacity
is lowered of class MainVm
.
This means by the bindings in XAML that the MainWindow is dimmed and a popup appears.
Pressing a button defined in the Popup will set Popup2IsOpen
to false.
<Button Command="{Binding ToggleOpenPopup2Command}" ..
<Popup IsOpen="{Binding Popup2IsOpen}" PopupAnimation="Slide" StaysOpen="False">
...
<StackPanel Background="White">
<GroupBox Header="Add a new name to save all current FolderTabs:" ... >
<StackPanel Orientation="Horizontal">
<TextBox Name="SaveItem" Text="Enter here.." ......../>
<Button Content="Add" Command="{Binding AddSavedTabsCommand}"
CommandParameter="{Binding Path=Text, ElementName=SaveItem}"/>
</StackPanel>
</GroupBox>
<Button Content="Cancel" Command="{Binding ToggleOpenPopup2Command}" Margin="5"/>
</StackPanel>
</Popup>
...
FileManagementButtonsView
At the last moment I wanted to have some provisory FileManagement. I tried a drag
and drop of the datagrid to another FolderTab but when starting a drag selected
items got deselected, as I understand it now the LeftMousedown changes the selection,
this seems a
familiar problem. I had no time left to introduce drag and drop properly
but since for testing I kept track of the selectedItems I decided to use some buttons
for provisory FileManagement. See figure below for the File Management buttons.
From left to right we see buttons:
- Take Snapshot of selected FolderPlaneItems
- Copy Snapshot to current selected folder
- Move
- Copy SnapShot (single folder) with date added to folder name
- New Folder
- Rename (uses Popup)
- Delete selected files
- Refresh FolderPlane and NavTree
- (Show Properties, not implemented)
The style for the round buttons can be found in MainResources.XAML. We set Background,
Content (string of 1-2 characters) and FontFamily. For the FontFamily I choose Segoe
Script, Wingdings, WebDings, Marlett etc. and I use OpenOffice to select and copy/paste
the Content string. This Button style is not so visual appealing but for a
first prototype it saves some time. The opacity is lowered when the button is not
enabled.
In XAML we bind these buttons to the commands specified in MainVm. A button that
bind to a command with the CanExecute test specified is conditionally enabled. For
example the right order for a copy is select items, Take Snapshot (Cntrl+V), click
on other folder tab, click on Copy button. So after the selection of FolderPlaneItems
the Take Snapshot button is enabled and opacity set higher (see figure above), after
clicking this button the Copy, Move, Copy with date (single file only) Buttons are
enabled etc.
What to do for a More Mature File Explorer
There is a lot of work to be done to make this toy a more functional File Explorer:
- More Testing
- File Management on background, User feedback.
- Drag and drop between selected files and other Tab and from/to Snapshot Button.
Visual feedback.
- Optionally introduce a MVVM Drag and Drop framework for the whole application.
- Context Menu for FolderPlane. Rightclick for copy/paste efficient, show properties.
- Implement History. History in W7 like Adresbar, TabsFolderPlane, TabbedNavTree.
- More RootItems in Tabbed Navigation Trees.
- Use Modal Windows using a service locator.
- Copy/Move from/to other application.
- Improve looks. Buttons, Folder Tabs pop up, Tabs NavTrees as list with no border,
Tabs popup when in area.
- Experiment with several settings. Two windows, make a popup of Tabbed Navigation
Trees.
- Options set by User.
We could target a more general File Explorer or a more specialised File Explorer.
The general W7 file explorer is excellent. For me for the specific task examined
the current prototype suffices and it is questionable if there is really a more
general interest in this approach. A new project seems more relevant, although the
introduction of a general MVVM drag and drop framework in this application is interesting.
Points of Interest
- Note that I am a little biased and I love Tabs in Visual Studio and
Notepad++ to keep some notes open. I introduced Tabbed Trees and Tabbed Folderplanes
and the possibility to load a group of Folder Tabs using only one click.
- The first observation is that the common automatisms of using context menu, drag
and drop and going back and forth with history fail.
- The way of working is to open first some Folder Tabs, by clicking on TreeItems or
opening a group at once by clicking on a saved named "Button".
- The specific task of copying a folder with date added the prototype is efficient.
Open a group of saved Folders, select the folder item, Take Snapshot Button, (click
on Tab to select other target Folder), click on Copy with date Button.
- My intention was to show one of the advantages of MVVM, the separation of control,
in a global way in this application. Note that the Model and ModelView are rather
compact.
- From this prototype I learnt a lot more about WPF.
- From this prototype I learnt some basic MVVM and the use of attached properties.
I now know some requirements to select a MVVM framework (Introduce INotify to properties
of a Model, map methods by convention on ICommands, support ViewModels/User Controls
cycle and communication between ViewModels, Modal windows).
- The implementation took longer then expected. Respect for those who make a fully
functional File Explorer!
- It is very tempting to introduce more features and make this prototype more mature.
- There are a few interesting tasks (Async, introduce a MVVM drag and drop framework,
more ViewModels) but a new project seems more relevant. In contrast to the trend
of very minimalistic interfaces I like to write one new desktop application with
a more interesting look.
- I am not sure of the future of the W7 desktop. How fast will W8 replace W7, what
are the costs for an upgrade? Windows 8 has two modes, one named "Desktop" and one
named "Metro style", see
here. What express editions will be available for desktop? Free express
editions seemed to target "Metro" however just before submitting this
article I read the good news of free Visual Express 2012 for desktop, see
here. I am very pleased with this news.
Limitations
- I did only limited testing on 1 Windows 7 PC.
- Prototype, minimal functionality.
- Very provisory File Management, no background process, no drag and drop etc.
- One known, not reproducible Bug. Selected folder for File Management incorrectly
set as the application directory (Empty string?)
History
2012-06-13 First Version article submitted.