Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A Toy Tabbed File Explorer for Prototype and MVVM Exercise

0.00/5 (No votes)
13 Jun 2012 2  
This article describes a Tabbed File Explorer with minimal functionality using only basic MVVM techniques and some attached properties. In a first article I described a MVVM Tabbed Navigation Tree, in this article I add a Tabbed Folderplane.

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:

  1. 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.
  2. 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.
  3. I sometimes make a copy of a single folder and add a date.
  4. 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

Global Design Tabbed File Explorer

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.

Project structure

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; }

    // For display (in TabItem)
    string FriendlyName { get; set; }

    // Sets the FolderPlaneItems 
    void SetFolderPlane(string path, bool clear = false);   
    void RefreshFolderPlane();

    //constructor: FolderPlane (string path);

    // Items displayed in FolderPlane
    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.

// snippets from MainVm, pseudo code properties
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

    // ShaderOpacy binding is used to set Opacity in MainWindow when a popup is open
    public double ShaderOpacity 
    public bool Popup1IsOpen; Popup2IsOpen; Popup3IsOpen

    // for file management
    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.

// from the setter of SelectedPath 
public string SelectedPath
{   .....
    string testValue = FolderPlaneUtils.ResolveIfShortCut(value); 
    .....
    // implementation of the INotifyPropertyChanged, see first article: 
    if (!SetProperty(ref selectedPath, testValue, "SelectedPath")) return;  
            
    // Design Choice: If in FolderPlanes: set SelectedFolderPlane to that and done 
    int indexInPlanes = GetIndexFolderPlanes(selectedPath);
    if (indexInPlanes != -1)
    {
        SelectedFolderPlane = FolderPlanes[indexInPlanes]; .... return;
    }

    FolderPlane newPlane = new FolderPlane();
    newPlane.SetFolderPlane(selectedPath);

    // UseCurrentPlane is set to true elsewhere ... when we move up or down a FolderPlane
    // Design Choice now: replace current SelectedFolder in FolderPlanes by newPlane
    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.
// pseudo code, snippets from MainVm, ICommands
public partial class MainVm
{
    public ICommand SelectedPathFromTreeCommand

    public ICommand FolderPlaneItemDoubleClickCommand

    public ICommand CloseTabCommand, FolderUpCommand

    public ICommand ToggleOpenPopup1Command, ToggleOpenPopup2Command, ToggleOpenPopup3Command

    public ICommand AddSavedTabsCommand, DeleteSavedTabsCommand, CloseAllFolderTabsCommand


    // Commands for FileMangement
    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.
// Snippets from MainViewWindow, only "UserControls" shown
// Grid definitions, Row and Columns properties, GridSplitter etc. ommited
    
  <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.

  // snippets from "UserControl" FolderPlaneView
  ....
  <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:

TabsFolderPlanesView

  • 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.

   // snippets from ListBox TabsFolderPlanesView "UserControl"

    <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">
      <!-- Hack, compact XAML, Menu with ComboBox; Width, MaxWidth and Margin tweaked  -->
      <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:

SavedFolderTabs

  • "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.

Popup

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.

  // Some snippets showing the use of a Popup for the Save Button

    <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:

FileManagementButtons

  • 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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here