-
Notifications
You must be signed in to change notification settings - Fork 263
File Explorer Programming Discussion
The ATF File Explorer Sample shows how to adapt controls to data. The folder view in the main window's left panel uses a TreeControl
with a TreeControlAdapter
, and the file panel on the right uses a System.Windows.Forms.ListView
with a ListViewAdapter
.
The sample also shows how to use MEF to add an arbitrary number of components to specify file information to display in a ListView
.
This page discusses the custom components added, such as FolderViewer
and FileViewer
, which control operations in the two panels of the main window. These components operate similarly, both creating controls and adapters that adapt the data to the control's view. The components each define a private view class, such as FileTreeView
, that implements interfaces for the adapters to provide capabilities like viewing and selection.
The sample defines an IFileDataExtension
interface that provides file and folder information. The sample defines several components that implement and export this interface. FileViewer
imports these components and iterates through them, so that it is easy to add an additional file information provider component.
FileExplorer follows the standard WinForms initialization pattern discussed in WinForms Application. In addition to standard ATF components, it adds the following components of its own to the MEF TypeCatalog
:
-
FolderViewer
: manage aTreeControl
to display a folder hierarchy of the computer's "C:" drive. For discussion, see FolderViewer Component. -
FileViewer
: manage aListView
to display the selected folder's contents. For details, see FileViewer Component. - File extension components implementing
IFileDataExtension
, which provides information about files and folders. For the details, see IFileDataExtension Exporter Components. There are three extensions defined:-
NameDataExtension
: extension inFileDataExtensions.cs
to display the folder or file name. -
SizeDataExtension
: extension inFileDataExtensions.cs
to display the file's size. -
CreationTimeDataExtension
: extension inFileDataExtensions.cs
to display folder or file creation time.
-
The FolderViewer
component's constructor creates a TreeControl
to display the hierarchical data of the "C:" drive's contents as a tree:
[ImportingConstructor]
public FolderViewer(MainForm mainForm, FileViewer fileViewer)
{
m_mainForm = mainForm;
m_fileViewer = fileViewer;
m_treeControl = new TreeControl();
m_treeControl.Text = "Folder Viewer";
m_treeControl.ImageList = ResourceUtil.GetImageList16();
m_treeControl.SelectionMode = SelectionMode.One;
m_treeControl.Dock = DockStyle.Fill;
m_treeControl.Text = "Folder Viewer";
m_treeControl.Width = 256;
m_treeControlAdapter = new TreeControlAdapter(m_treeControl);
m_fileTreeView = new FileTreeView();
m_fileTreeView.SelectionChanged += new EventHandler(fileTreeView_SelectionChanged);
m_treeControlAdapter.TreeView = m_fileTreeView;
}
The FileViewer
parameter imported is a FileViewer
object, discussed in FileViewer Component.
The constructor sets various properties of the new TreeControl
. For example, the ImageList
property is set to a list of image resources, so that an image can be used for folders in the TreeControl
. The SelectionMode
property is set so that only one item can be selected at a time.
After setting the TreeControl
's properties, the constructor creates a TreeControlAdapter
for that tree, which adapts the TreeControl
to a data context that implements ITreeView
. Finally, a new FileTreeView
is created, which adapts the "C:" drive's contents to a tree of selectable items.
The component's IInitializable.Initialize()
method sets the left panel of the main window to the newly created TreeControl
:
void IInitializable.Initialize()
{
m_mainForm.SplitContainer.Panel1.Controls.Add(m_treeControl);
}
The handler for the SelectionChanged
event sets the Path
property of the imported FileViewer
component to the path of the selected folder:
private void fileTreeView_SelectionChanged(object sender, EventArgs e)
{
Sce.Atf.Path<object> lastPath = m_fileTreeView.LastSelected as Sce.Atf.Path<object>;
if (lastPath != null)
{
FileSystemInfo info = lastPath.Last as FileSystemInfo;
if (info is DirectoryInfo)
m_fileViewer.Path = info.FullName;
}
}
FileViewer
's Path
determines what is displayed in the right panel of the main window, which is discussed in FileViewer Component.
FolderViewer
uses this TreeControlAdapter
constructor:
public TreeControlAdapter(TreeControl treeControl)
: this(treeControl, null)
{
}
This constructor invokes the actual constructor used:
public TreeControlAdapter(TreeControl treeControl, IEqualityComparer<object> comparer)
{
m_treeControl = treeControl;
m_itemToNodeMap = new Multimap<object, TreeControl.Node>(comparer);
m_treeControl.MouseDown += treeControl_MouseDown;
m_treeControl.MouseUp += treeControl_MouseUp;
m_treeControl.DragOver += treeControl_DragOver;
m_treeControl.DragDrop += treeControl_DragDrop;
m_treeControl.NodeExpandedChanged += treeControl_NodeExpandedChanged;
m_treeControl.NodeSelectedChanged += treeControl_NodeSelectedChanged;
m_treeControl.SelectionChanging += treeControl_SelectionChanging;
m_treeControl.SelectionChanged += treeControl_SelectionChanged;
}
This code subscribes to event handlers for mouse operations, drag and drop, node expansion/contraction, and selection changes. This sample application uses all these events, except the drag and drop ones.
TreeControlAdapter
has a TreeView
property, shown here with its comments:
/// <summary>
/// Gets or sets the tree displayed in the control. When setting, consider having the
/// ITreeView object also implement IItemView, IObservableContext, IValidationContext,
/// ISelectionContext, IInstancingContext, and IHierarchicalInsertionContext.</summary>
public ITreeView TreeView
...
Recall that FolderViewer
's constructor sets this TreeView
property to the newly created FileTreeView
, which implements ITreeView
:
m_fileTreeView = new FileTreeView();
m_fileTreeView.SelectionChanged += new EventHandler(fileTreeView_SelectionChanged);
m_treeControlAdapter.TreeView = m_fileTreeView;
It also subscribes the FileTreeView
to the SelectionChanged
event, whose handler was shown previously.
FileTreeView
is a private class that implements ITreeView
for TreeControlAdapter
:
private class FileTreeView : ITreeView, IItemView, ISelectionContext
Its constructor sets up a new Selection
object:
public FileTreeView()
{
m_selection = new Selection<object>();
m_selection.Changed += new EventHandler(selection_Changed);
// suppress compiler warning
if (SelectionChanging == null) return;
}
Selected items in the tree represent folders, and Selection
provides what's needed to select these items. FileTreeView
works mainly with System.IO.DirectoryInfo
objects, which encapsulate information for a directory.
FileTreeView
implements several interfaces.
ITreeView
generalizes a tree to a root with child objects:
-
Root
: property for the root object of the tree view. -
GetChildren()
: get children of the given parent.
ITreeView
implementation works with file system objects, as seen in the next code example. Root
simply returns directory information for the "C:" drive, because m_path
is initialized to "C:\". GetChildren()
gets the files and folders in a parent folder.
public object Root
{
get { return new DirectoryInfo(m_path); }
}
public IEnumerable<object> GetChildren(object parent)
{
IEnumerable<object> result = null;
DirectoryInfo directoryInfo = parent as DirectoryInfo;
if (directoryInfo != null)
result = GetSubDirectories(directoryInfo); //may return null
if (result == null)
return EmptyEnumerable<object>.Instance;
return result;
}
The private method GetSubDirectories()
gets the contents of a directory, as an array of DirectoryInfo
objects.
IItemView
continues the work with the file system. Its GetInfo()
method fills out an ItemInfo
with information from a DirectoryInfo
: the folder name, including whether it's a leaf, that is, whether it contains no files or folders.
public void GetInfo(object item, Sce.Atf.Applications.ItemInfo info)
{
DirectoryInfo directoryInfo = item as DirectoryInfo;
if (directoryInfo != null)
{
info.Label = directoryInfo.Name;
info.ImageIndex = info.GetImageList().Images.IndexOfKey(Resources.ComputerImage);
DirectoryInfo[] directories = GetSubDirectories(directoryInfo);
info.IsLeaf =
directories != null &&
directories.Length == 0;
}
}
ItemInfo
's ImageIndex
property is set to display a computer icon for each item in the tree view, using standard ATF image resources from the Resources
class.
ISelectionContext
is the general interface for selections. It's very easy to implement here, because the constructor created a Selection
object:
m_selection = new Selection<object>();
This interface implementation uses the Selection
class's methods to provide everything ISelectionContext
needs. For instance, GetSelection<T>()
does this:
public IEnumerable<T> GetSelection<T>()
where T : class
{
return m_selection.AsIEnumerable<T>();
}
This interface also includes the SelectionChanged
event, which is raised after the selection changes. This is important, because changing the selected item in the tree representation of the "C:" drive determines what's displayed in the right panel of the main window. As previously mentioned, this event's handler places the selected folder's path in FileViewer
's Path
property, which governs which folder's contents appear in FileViewer
's ListView
in the main window's right panel.
FileViewer
displays the contents of a folder using a ListView
control and parallels FolderViewer
in its operation. FileViewer
's constructor does basically the same things as FolderViewer
's constructor: it creates a control, configures it, and then creates an adapter for the control. FileViewer
creates a ListView
rather than a TreeControl
:
[ImportingConstructor]
public FileViewer(MainForm mainForm)
{
m_mainForm = mainForm;
// create a standard WinForms ListView control
m_listView = new ListView();
m_listView.Dock = DockStyle.Fill;
m_listView.Text = "File Viewer";
m_listView.BackColor = SystemColors.Window;
m_listView.SmallImageList = ResourceUtil.GetImageList16();
m_listView.AllowColumnReorder = true;
// create an adapter to drive the ListView control
m_listViewAdapter = new ListViewAdapter(m_listView);
m_fileListView = new FileListView();
}
The new ListView
's SmallImageList
property is set to display small icons for files and folders in the ListView
.
After the ListView
's properties are set, a ListViewAdapter
for that list is created. A ListViewAdapter
adapts a ListView
to a data context that implements IListView
. Finally, a new FileListView
is created, which adapts a directory to an observable list of items, that is, the folders and files in the selected folder in the TreeControl
.
The component's IInitializable.Initialize()
method accomplishes the following:
- Makes a list of all the
IFileDataExtension
providers, which were imported into them_extensions
field:
[ImportMany] // gets all file data extensions
private IEnumerable<Lazy<IFileDataExtension>> m_extensions = null;
- Sets the
ListViewAdapter
'sListView
property to the newFileListView
. - Adds the newly created
ListView
to the right panel of the main window.
void IInitializable.Initialize()
{
// pass all file data extensions to adapter
List<IFileDataExtension> list = new List<IFileDataExtension>();
foreach (Lazy<IFileDataExtension> extension in m_extensions)
list.Add(extension.Value);
m_fileListView.FileDataExtensions = list.ToArray();
// set the adapter's ListView to an adapter that returns directory contents
m_listViewAdapter.ListView = m_fileListView;
m_mainForm.SplitContainer.Panel2.Controls.Add(m_listView);
SettingsServices.RegisterSettings(
m_settingsService,
this,
new BoundPropertyDescriptor(this, () => ListViewSettings, "ListViewSettings", null, null));
}
FileViewer
's Path
property gets or sets the path to the folder whose contents are displayed in the ListView
:
public string Path
{
get { return m_fileListView.Path; }
set
{
m_fileListView.Path = value;
m_mainForm.Text = value;
}
}
Note that this property simply accesses the Path
property of the FileListView
object. As discussed previously, FileViewer
's Path
property is set to the currently selected file path in the tree view when the selection changes by the FolderViewer
's SelectionChanged
event handler.
FileViewer
uses this ListViewAdapter
constructor:
public ListViewAdapter(ListView listView)
{
m_control = listView;
m_control.View = View.Details;
m_control.FullRowSelect = true;
m_control.HideSelection = false;
// default to allow sorting
m_allowSorting = true;
m_control.ListViewItemSorter = new ListViewItemSorter(m_control);
m_control.AfterLabelEdit += control_AfterLabelEdit;
m_control.ColumnWidthChanged += control_ColumnWidthChanged;
m_control.MouseDown += control_MouseDown;
m_control.MouseUp += control_MouseUp;
m_control.DragOver += control_DragOver;
m_control.DragDrop += control_DragDrop;
}
This code subscribes to event handlers for label and column changes, mouse operations, and drag and drop. This sample uses all these events, except the drag and drop ones.
ListViewAdapter
has a ListView
property, which gets or sets the IListView
object for the list data. FileViewer
's IInitializable.Initialize()
method sets this property to the FileListView
object, which implements IListView
:
// set the adapter's ListView to an adapter that returns directory contents
m_listViewAdapter.ListView = m_fileListView;
FileListView
is analogous to the FileTreeView
that TreeControlAdapter
uses and serves much the same function: to handle data in the view, a list view in this case — rather than a tree view.
FileListView
is a private class that implements IListView
for the ListViewAdapter
:
private class FileListView : IListView, IItemView, IObservableContext
This class does not implement selection, but it does implement several other interfaces. Although it implements IObservableContext
, which contains events, it does not raise these events.
IListView
is the main interface used with ListView
controls and abstracts an enumeration of objects that can be used as tags, one per row, in a list control, along with corresponding user-readable column names at the top.
The ColumnNames
property provides an array of strings for the column names:
public string[] ColumnNames
{
get
{
string[] result = new string[m_fileDataExtensions.Length];
for (int i = 0; i < result.Length; i++)
result[i] = m_fileDataExtensions[i].ColumnName;
return result;
}
}
ColumnNames
enumerates the IFileDataExtension
providers to get the ColumnName
property for each one. Recall how m_fileDataExtensions
was set up to contain all the IFileDataExtension
providers:
List<IFileDataExtension> list = new List<IFileDataExtension>();
foreach (Lazy<IFileDataExtension> extension in m_extensions)
list.Add(extension.Value);
m_fileListView.FileDataExtensions = list.ToArray();
And m_extensions
is the field into which all the IFileDataExtension
providers are imported:
[ImportMany] // gets all file data extensions
private IEnumerable<Lazy<IFileDataExtension>> m_extensions = null;
For further explanation of how IFileDataExtension
is used, see IFileDataExtension Exporter Components.
The IListView.Items
property contains all the items that the ListView
displays. That is, it displays all the files and folders in the folder selected in the TreeControl
in the left panel of the main window. Therefore, Items
uses the m_path
field, which, as previously noted, contains the currently selected file path in the tree view. Items
uses DirectoryInfo
methods to get lists of all the directories and files in the path specified by m_path
:
public IEnumerable<object> Items
{
get
{
if (m_path == null ||
!Directory.Exists(m_path))
{
return EmptyEnumerable<object>.Instance;
}
DirectoryInfo directory = new DirectoryInfo(m_path);
DirectoryInfo[] subDirectories = null;
try
{
subDirectories = directory.GetDirectories();
}
catch
{
}
if (subDirectories == null)
subDirectories = new DirectoryInfo[0];
FileInfo[] files = null;
try
{
files = directory.GetFiles();
}
catch
{
}
if (files == null)
files = new FileInfo[0];
List<object> children = new List<object>(subDirectories.Length + files.Length);
children.AddRange(subDirectories);
children.AddRange(files);
return children;
}
}
IItemView
gets information about individual file or folder items to display in the view. This interface was also implemented by FileTreeView
to display information about folders in the tree view.
GetInfo()
fills out a given ItemInfo
object to display item's information in the ListView
:
public void GetInfo(object item, ItemInfo info)
{
// set the first column info (name)
FileSystemInfo fileSystemInfo = item as FileSystemInfo;
if (fileSystemInfo is DirectoryInfo)
{
info.Label = fileSystemInfo.Name;
info.ImageIndex = info.GetImageList().Images.IndexOfKey(Resources.FolderImage);
}
else if (fileSystemInfo is FileInfo)
{
info.Label = fileSystemInfo.Name;
info.ImageIndex = info.GetImageList().Images.IndexOfKey(Resources.DocumentImage);
info.IsLeaf = true;
}
// set the 2nd and 3nd columns info (size and creation time)
info.Properties = new string[m_fileDataExtensions.Length-1];
for (int i = 0; i < info.Properties.Length; i++)
info.Properties[i] = m_fileDataExtensions[i+1].GetValue(fileSystemInfo);
}
GetInfo()
casts the item to FileSystemInfo
and determines whether it specifies information for a folder or file. It obtains the item's name and the appropriate image, depending on whether its a folder or file. Similarly to the implementation of IListView.ColumnNames
, this property iterates the IFileDataExtension
providers in m_fileDataExtensions
to get file or folder information and then add it to the ItemInfo
's Properties
array.
This sample creates the IFileDataExtension
interface to define components that provide file information for a given FileSystemInfo
object. These components get the folder and file information displayed in FileViewer
's ListView
. As will be seen, you can easily add similar components to display additional information about folders and files.
IFileDataExtension
defines two items in its interface:
-
string ColumnName
property: get astring
for the column name in theListView
for the file information. This information is obtained forFileListView
'sIListView.ColumnNames
property, as described in FileListView Class. -
string GetValue(FileSystemInfo fileSystemInfo)
method: get astring
value describing file information, such as a size or creation time, from a givenFileSystemInfo
.FileListView
'sIItemView.GetInfo()
method uses this to get the information displayed in theListView
.
The file FileDataExtension.cs
contains several components that export IFileDataExtension
. These components are imported by FileViewer
, as previously described.
Note that FileViewer
imports these components using [ImportMany]
, so that an arbitrary number of these components can be imported. In addition, FileViewer
iterates through the list of imported IFileDataExtension
providers, so that it is easy to add an additional provider.
All these components operate pretty much the same. For example, here's the CreationTimeDataExtension
component that obtains the creation time:
[Export(typeof(IFileDataExtension))]
public class CreationTimeDataExtension : IFileDataExtension
{
/// <summary>
/// Gets the name of the column</summary>
public string ColumnName
{
get { return "Creation Time"; }
}
/// <summary>
/// Gets the value for the column and given file system item</summary>
/// <param name="fileSystemInfo">Info describing the file or directory</param>
/// <returns>Value for the column and given file system item</returns>
public string GetValue(FileSystemInfo fileSystemInfo)
{
return fileSystemInfo.CreationTime.ToString(CultureInfo.CurrentCulture);
}
}
ColumnName
simply provides a string
for the name to be used as the column label in the ListView
.
GetValue()
extracts the creation time from the given FileSystemInfo
, returning it as a string.
- Circuit Editor Programming Discussion: Learn how ATF handles graphs, and provides editors for kinds of graphs, such as circuits.
- Code Editor Programming Discussion: Shows how to interface third party software to an ATF application: the ActiproSoftware SyntaxEditor.
- Diagram Editor Programming Discussion: Very simply combines components from the CircuitEditor, FsmEditor, and StateChartEditor samples into one application, with the abilities of all three, showing the power of components.
-
DOM Property Editor Programming Discussion: Shows how to use the ATF DOM with an XML Schema to define application data with a large variety of attribute types, whose values can be viewed and edited using the ATF
PropertyEditor
component, using various value editors to view and edit attributes. - DOM Tree Editor Programming Discussion: Shows how to edit DOM data using a tree control and display properties in a variety of value editors.
- File Explorer Programming Discussion: Discusses the ATF File Explorer Sample using list and tree controls with adapters.
- FSM Editor Programming Discussion: Tells you about how the ATF FSM Editor Sample edits simple graphs for state machines, using DOM adapters for contexts and validation.
-
Model Viewer Programming Discussion: Shows how the ATF Model Viewer Sample is written, discussing how ATGI and Collada model data is handled, using rendering components, and using a
DesignControl
as a canvas for rendering. -
Simple DOM Editor Programming Discussion: Programming the ATF Simple DOM Editor Sample, creating a palette, using DOM adapters and contexts, editing application data, and searching
DomNode
s. - Simple DOM Editor WPF Programming Discussion: Programming the ATF Simple DOM Editor WPF Sample, which is similar to ATF Simple DOM Editor Sample, but implemented using ATF's WPF framework.
- Simple DOM No XML Editor Programming Discussion: Programming the ATF Simple DOM No XML Editor Sample, which is very similar to ATF Simple DOM Editor Sample, except that it doesn't use XML for either its data model or persisting application data.
- State Chart Editor Programming Discussion: Shows using ATF graph and other classes to create a statechart editor, using DOM adapters, documents, contexts, and validators.
- Target Manager Programming Discussion: Description of how a target manager is implemented using ATF components to manage target devices, such as PlayStation®Vita or PS3™ consoles. A target manager is used in other tools, such as the StateMachine tool.
- Timeline Editor Programming Discussion: Discusses how to create a fairly full-featured timeline editor using the ATF timeline facilities, such as the timeline renderer and the timeline control and its manipulators.
-
Tree List Control Programming Discussion: Demonstrates using the
TreeListControl
andTreeListItemRenderer
classes to display and edit hierarchical data in a tree view with details in columns. -
Tree List Editor Programming Discussion: Demonstrates how to use the ATF tree controls
TreeListView
and its enhancement,TreeListViewEditor
.TreeListView
usesTreeListViewAdapter
, which adaptsTreeListView
to display data in a tree. - Using Dom Programming Discussion: Shows how to use the various parts of the ATF DOM: an XML Schema, a schema metadata class file generated by DomGen, DOM adapters for the data types, a schema loader, and saving application data to an XML file.
- Home
- Getting Started
- Features & Benefits
- Requirements & Dependencies
- Gallery
- Technology & Samples
- Adoption
- News
- Release Notes
- ATF Community
- Searching Documentation
- Using Documentation
- Videos
- Tutorials
- How To
- Programmer's Guide
- Reference
- Code Samples
- Documentation Files
© 2014-2015, Sony Computer Entertainment America LLC