Me Myself & C#

Manoj Garg’s Tech Bytes – What I learned Today

Problem with Webdev.webserver.exe when working with web services with non-fixed ports

Posted by Manoj Garg on May 6, 2009

Yesterday, a team mate of mine sent an email regarding a problem with his Visual Studio 2005. ASP.NET web server wasn’t allowing him to debug any Web services. Following is the complete description of his problem:

Summary

In short, the ASP.NET 2.0 development web server (webdev.webserver.exe) on my machine broke after I installed and uninstalled NDoc some days ago. IIS still works fine. I’ve tried re-registering ASP.NET 2.0 (aspnet_regiis –r from the 2.0 directory) to no avail. Other than re-installing VS 2005, could you recommend a quick fix?

Problem Description

I am on XP. I had VS 2005 with v2.0 of the framework. Then I installed NDoc recently and that supports only v1.1, so it installed v1.1 on top of v2.0. That is fine because both versions can co-exist but what it did was screw up some settings with:
a) The web server that comes with ASP.NET, the one you run your web services on in debug mode.
b) SQL Server’s active CLR settings (but this isn’t bothering me as much)
c) IIS settings (but I fixed this by re-registering IIS with 2.0)
What’s bothering me to the hilt now is the broken ASP.NET web server won’t allow me to debug my Web services or even have another project in the same solution create a web reference to it.
I can’t generate proxies in Visual Studio because of this, nor can I set a web reference to a web service in the same solution (as it involves generating a proxy).
Note that I can call wsdl.exe though. My web services compile, and if I generate a proxy myself through wsdl.exe, deploy my WS locally on IIS, and change the url in the proxy’s constructor to my locally deployed WS, and add the proxy to my client project, it all works fine.

But I don’t want to deploy my service yet. I just want all projects in the same solution referencing the ws like well-behaved little kids.
When I do try to create a web reference to the WS project in my solution, I keep getting this error:
Server Error in ‘/’ Application.
——————————————————————————–
Parser Error
Description: An error occurred during the parsing of a resource required to service this request. Please review the following specific parse error details and modify your source file appropriately.
Parser Error Message: Could not create type ‘DaWS.PhoneDirectory’.
Source Error:
Line 1:  <%@ WebService Language="C#" CodeBehind="PhoneDirectory.asmx.cs"
Line 2:  Class="DaWS.PhoneDirectory" %>
Source File: /PhoneDirectory.asmx    Line: 2
——————————————————————————–
Version Information: Microsoft .NET Framework Version:2.0.50727.3082; ASP.NET Version:2.0.50727.3082
It’s been nagging me for days now and I’ve been managing with deploying in IIS.
Other than re-install Visual Studio, does anyone have a better solution?
Here’s what the Event Log says:
Event Type:    Warning
Event Source:    ASP.NET 2.0.50727.0
Event Category:    Web Event
Event ID:    1310
Date:        06/05/2009
Time:        12:04:33 AM
User:        N/A
Computer:    ABCD
Description:
Event code: 3006
Event message: A parser error has occurred.
Event time: 06/05/2009 12:04:33 AM
Event time (UTC): 05/05/2009 6:34:33 PM
Event ID: c41a610193fa4c2e810dad096709b0b0
Event sequence: 4
Event occurrence: 1
Event detail code: 0
Application information:
    Application domain: a54e0deb-1-128860220726250000
    Trust level: Full
    Application Virtual Path: /
    Application Path: C:\Me\rnd\DotNet\DoIndexersGetSerialized\DaWS\
    Machine name: ABCD
Process information:
    Process ID: 660
    Process name: webdev.webserver.exe
    Account name: Domain\Me

Some one finally caught the issue, following are his observations and solution:

Just wondering if you are using a fixed port or not for the web service that you try to reference. Because Web Dev by default always host the app on different port and if that the case you will not be able to get it working ever.

If you are not using the fixed port I would suggest you to use the “External Tool” options present in the VS’s Tool menu and create a fixed web dev location that is associated with you web service and you should be able get it working.

I may be telling you the thing that you might have tried but just incase if you haven’t please give it a try.

Please have a look at this URL and probably give you the solution you are looking for.

http://weblogs.asp.net/scottgu/archive/2005/11/21/431138.aspx

This did the trick. The problem was solved. So I thought to write it here as someone else may face the same issue. 🙂

Advertisements

Posted in .Net 2.0, ASP.Net, VS 2005 | Tagged: , , , | 4 Comments »

Passing an object by REF inside a foreach loop

Posted by Manoj Garg on April 22, 2009

Its summer time in India and its hard to resist drowsiness in the afternoon specially when you had a heavy lunch. So this afternoon while I was trying to take a nap, no one was watching :P, a friend of mine pinged me on IM, and says “dude, can’t I pass an object as ref inside a foreach loop?”, well my first reaction was “of course you can!!! “ but then I realized that its an iterator  and I can’t modify an object I am iterating on.

I opened a new instance of Visual Studio and create a new console application. In this application created a new class named testref with just two fields, one string and another one an int. In the main method created a generic list of type testref and filled it with five testref object. Then tried to loop through it and pass the loop variable as ref in a function. He was right, C# compiler throws an error “Cannot pass ‘xxyzobj’ as a ref or out argument because it is a ‘foreach iteration variable’”. following snippet shows the initial set of code

 class Program
    {
        class testref
        {
            public string val { get; set; }
            public int a {get;set;}

            public testref(string s)
            {
                val = s;
                a = 0;
            }
        }

        static void Main(string[] args)
        {
            List<testref> testcol = new List<testref>();

            testcol.Add(new testref("One"));
            testcol.Add(new testref("two"));
            testcol.Add(new testref("three"));
            testcol.Add(new testref("four"));
            testcol.Add(new testref("five"));

            foreach (testref s in testcol)
            {            
               MethodWithRef(ref s);
            }

            Console.ReadLine();
            
        }

        static void MethodWithRef(ref testref str)
        {
            str.val = str.val + " not";
            str.a = (new Random()).Next();
        }

}

In above code snippet, line in yellow will give the compilation error. Since this is a C# complier restriction there are couple of workaround to this situation.

  • Have a temporary variable and then pass this variable as the ref parameter in the method:
testref tempObj;
foreach (testref s in testcol)
{
    tempObj = s;
    MethodWithRef(ref tempObj);
}
  • Use List.ForEach() method to apply an action on all the objects in the list:
// Inside the main method pass the function name 
// you want to apply on each object
testcol.ForEach(MethodWithoutRef);

//Method to be applied on all the objects
static void MethodWithoutRef(testref str)
{
   str.val = str.val + " not";
   str.a = (new Random()).Next();
}

So that was it.. problem was solved…

PS: If you have some more ways this can be solved, Please do share.

Manoj

Posted in C#, Collections & Generics | Tagged: | Leave a Comment »

Credit Crisis: How it happened??

Posted by Manoj Garg on April 9, 2009

Well nowadays everyone says, its economic downturn these days.. World economy is going through troubled times.. World is under recession … so on n so forth.. All headlines related to this have one word in common . CREDIT CRISIS .. I always wondered how it all started… So while stumbling across the web found 2 videos giving a good visualization and answer to the big question … How It all started…? so thought of sharing these with all..

 

 

 

Posted in Non Technical | Tagged: , | 1 Comment »

2009: Top 5 April Fool gags

Posted by Manoj Garg on April 2, 2009

Every year 1st April brings lots of funny email circulating around asking you to do strange things to get strange results 😛 (of course a h1 styled “April Fool” message floating on your computer screen).

Google comes with some amazing stuff every year on this EVE (he he). I eagerly wait for this day to see what they are gonna tell the world they are introducing today. This year they wrote a blog entry about CADIE taking over the online search.

But this time I like the one gag by OPERA team for introducing the Intuitive Browsing using Face gestures

This year’s top 5 gags are posted here. I found each one of them very good.

Posted in Non Technical | Tagged: , , , , | Leave a Comment »

Gmail says “you can Undo it”

Posted by Manoj Garg on March 30, 2009

Ever had a bad day with your composed email. when you wanted to send it to someone or type in wrong subject forgot to attach a file and by unknowingly clicked “SEND”. GMAIL team has come up with a solution to save you from such situations by giving you a chance to UNDO the sent email.

Google Labs is providing an option of giving an Undo link after you click on the send button. But the catch is You have got 5 seconds to undo it else its gone.

To read more about this feature and its usage read here @ Official Gmail Blog.

Hope it saves you some time 🙂

Posted in Non Technical | Tagged: , | Leave a Comment »

WPF 101 : Custom Expander Control to show a popup on mouse over

Posted by Manoj Garg on March 29, 2009

This is the second post in this WPF learning series. In this post I will be writing about creating your own custom controls in WPF. I am going to write a custom expander which has similar features as of the WPF expander control plus it will have a feature of showing a Popup on mouse over event of this expander. Content of this popup will be the content of the expander itself. This is the kind of feature where a user wants to see the content of expander while hovering the mouse over the expander header, just like IE8 tab quick preview where it shows a preview of tab content without even opening the tab. So below are our set of requirements:

Requirements

  • It should be an expandable control with a header and content property.
  • It should show a popup when mouse is over the header and control is in collapsed state.
  • Should have an option for showing/hiding the popup.
  • Popup properties like position, size, transparency etc should be configurable.

Choosing the Proper base class

While writing a custom control one must choose the base control which he/she wants to extend with little care with having all the features in mind. For our requirements, we need a base class which provides me a header, a content property. In WPF we have some choices like HeaderedContentControl class and we have an Expander class which itself drives from HeaderedContentControl class. we can use any of them. I decided to use Expander class (well while coding I wasn’t sure what all I wanted to have 😉 ).

Implementation

Visual studio 2008 provides a project of type “WPF Custom Control Library” which can be used as a starting point for writing your first custom control. Following figure shows the selection of new project type.

newcustomcontrol

When adding this project type to your visual studio solution, it will add a new project with following items to your solution structure:

  1. CustomControl1.cs: This file contains your custom control class.
  2. Themes Folder with Generic.xaml: This folder will contain the styles for all your custom controls. By default a new style for the customcontrol1 is added to the generic.xaml. One needs to change this style to work with this custom control.

Lets start implementing the new expander with popup. As we have decided we will be using Expander class as the base class for our control. I will be naming this control as CustomExpander.

  1: namespace CustomControls
  2: {
  3:     /// <summary>
  4:     /// This class is an extention to Expander Control. 
  5:     /// This provides a feature for shouwing a popup with the content of the expander on MouseOver
  6:     /// </summary>
  7:     public class CustomExpander : Expander
  8:     {
  9:         #region // .ctor(s)
 10:         static CustomExpander()
 11:         {
 12:             DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomExpander), new FrameworkPropertyMetadata(typeof(CustomExpander)));
 13:         }
 14:         public CustomExpander()
 15:         {
 16:         }
 17:         #endregion
 18:     }
 19: }

The above class definition has a static ctor and a normal default ctor for the CustomExpander class. The static ctor is used to initialize the static properties of the class as well as changing the default style for the control. As highlighted in the above code snippet in line 12, DefaultStyleKeyProperty is used to change the default style for the control by passing the type of the new control.

Now we have to decide upon what all configurable properties we want to expose to the end user of this control. As mentioned in the requirement section above, we will have following dependency properties in our control:

  1. PopUpPlacementModeProperty: This property will allow user to configure the placement of popup in the screen. This is of type PlacementMode.
  2. StaysOpenProperty: This property defines whether the popup will stay open when the popup looses focus. This is of type Boolean.
  3. AllowsTransparencyProperty: This property allows user to set the transparency for the popup. This is a Boolean value.
  4. PopUpWidthProperty: Width of the popup. This is of type Double
  5. PopUpHeightProperty: Height of the popup. This is of type Double

Now lets us decide what controls we will be using to give this control a look of an Expander. For Expander functionality I will use ToggleButton control and a ContentPresenter control. since toggle button has the notion of being in two state (clicked and non clicked), so these state we can use to denote expanded and collapsed state of the expander. For popup functionality we will use wpf PopUp control.

So here is our task, on mouse hover on the togglebutton, set content of the expander as the child of  popup. and on click of the expander show the contentpresenter . 🙂  simple enough .. hmmmmmm

But here comes the issue. As we are talking about setting the content of popup same as the content of the expander but any object/ control can be child of only one parent. So we need make sure that while we show the popup or expand the expander only one of them have their content property set and the other one has this as null. To accomplish this we need one more dependency property which will store the content of the expander and we will use this property as the child for popup as well expander but only one at a time.

  1: public static readonly DependencyProperty OldContentProperty =
  2:                    DependencyProperty.Register("OldContent", typeof(object), typeof(CustomExpander));
  3:
  4: private object OldContent
  5: {
  6:      get { return GetValue(OldContentProperty); }
  7:      set { SetValue(OldContentProperty, value); }
  8: }
  9:

Now lets create the style for Expander. First lets design the header for the Expander. So we need a circle with an arrow indicating the expand/collapse direction and a content presenter showing the text of the header. Following code shows the style for the toggle button header.

  1: <!-- Style for the toggle button which wil be used as expander header -->
  2: <Style TargetType="{x:Type ToggleButton}" x:Key="toggleButtonKey">
  3:      <Setter Property="Template">
  4:           <Setter.Value>
  5:                 <ControlTemplate TargetType="{x:Type ToggleButton}">
  6:                        <StackPanel Orientation="Horizontal"
  7:                                  Margin="{TemplateBinding Padding}">
  8:                               <Grid Background="Transparent">
  9:                                    <!-- Circles for the expander header containg the expand direction arrow -->
 10:                                    <Ellipse x:Name="circle"
 11:                                             HorizontalAlignment="Center" VerticalAlignment="Center"
 12:                                             Width="20" Height="20"
 13:                                             Stroke="DarkGray"/>
 14:                                    <Ellipse x:Name="shadow" Visibility="Hidden"
 15:                                             HorizontalAlignment="Center" VerticalAlignment="Center"
 16:                                             Width="17" Height="17" />
 17:
 18:                                    <!-- Expand direction Arrow -->
 19:                                    <Path x:Name="arrow"
 20:                                             VerticalAlignment="Center" HorizontalAlignment="Center"
 21:                                             Stroke="#666" StrokeThickness="2"
 22:                                             Data="M1,1 L4,4 7,1" />
 23:                               </Grid>
 24:
 25:                               <!-- Expander Header Content -->
 26:                               <ContentPresenter ContentSource="{TemplateBinding Content}" Grid.Column="1" Margin="5"/>
 27:                        </StackPanel>
 28:
 29:                        <ControlTemplate.Triggers>
 30:                              <!-- Trigger to change the arrow direction when expanded -->
 31:                              <Trigger Property="IsChecked" Value="true">
 32:                                     <Setter TargetName="arrow"
 33:                                             Property="Data" Value="M 1,4  L 4,1  L 7,4"/>
 34:                              </Trigger>
 35:
 36:                              <!-- Trigger to give a mouse over effect on the circle containing direction arrow -->
 37:                              <Trigger Property="IsMouseOver" Value="true">
 38:                                     <Setter TargetName="circle"
 39:                                             Property="Stroke" Value="#666"/>
 40:                                     <Setter TargetName="arrow"
 41:                                             Property="Stroke" Value="#222"/>
 42:                                     <Setter TargetName="shadow"
 43:                                             Property="Visibility" Value="Visible"/>
 44:                               </Trigger>
 45:                       </ControlTemplate.Triggers>
 46:               </ControlTemplate>
 47:         </Setter.Value>
 48:    </Setter>
 49: </Style>

Now the expander content and popup.

  1: <!-- Expander -->
  2:                             <StackPanel>
  3:                                     <!-- Expander Header -->
  4:                                     <ToggleButton x:Name="expanderHeader"
  5:                                               Style="{StaticResource toggleButtonKey}"
  6:                                               Content="{TemplateBinding Header}"
  7:                                               Padding="{TemplateBinding Padding}"
  8:                                               IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsExpanded,Mode=TwoWay}"/>
  9:
 10:                                     <!-- Expander Content -->
 11:                                     <ContentPresenter x:Name="expanderContent"/>
 12:                             </StackPanel>
 13:
 14:                             <!-- PopUp control which will be showing the content of expander on mouse over -->
 15:                             <Popup x:Name="contentPopUp"
 16:                                    IsOpen="False"
 17:                                    Placement="{TemplateBinding PopUpPlacementMode}"
 18:                                    AllowsTransparency = "{TemplateBinding AllowsTransparency}"
 19:                                    StaysOpen = "{TemplateBinding StaysOpen}"
 20:                                    Width="{TemplateBinding PopUpWidth}"
 21:                                    Height="{TemplateBinding PopUpHeight}">
 22:                             </Popup>

Finally the triggers which would show the popup on mouse over and set the content.

  1: <ControlTemplate.Triggers>
  2:                         <!-- Trigger for showing the popup when Expander control is not expanded and IsMouseOver is true  -->
  3:                         <MultiTrigger>
  4:                             <MultiTrigger.Conditions>
  5:                                 <Condition SourceName="expanderHeader" Property="IsMouseOver" Value="True"></Condition>
  6:                                 <Condition SourceName="expanderHeader" Property="IsChecked" Value="False"></Condition>
  7:                             </MultiTrigger.Conditions>
  8:                             <Setter TargetName="expanderContent"
  9:                                     Property="Content" Value="{x:Null}"></Setter>
 10:                             <Setter TargetName="contentPopUp"
 11:                                     Property="Child" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=OldContent,Mode=OneWay,Converter={StaticResource localConverter}}"></Setter>
 12:                             <Setter TargetName="contentPopUp"
 13:                                     Property="BitmapEffect" Value="{StaticResource outerGlow}"></Setter>
 14:                             <Setter TargetName="contentPopUp"
 15:                                     Property="IsOpen" Value="True"></Setter>
 16:                         </MultiTrigger>
 17:
 18:                         <!-- Trigger for clearing the content of PopUp control when mouse is not over the expander control -->
 19:                         <Trigger SourceName="expanderHeader" Property="IsMouseOver" Value="False">
 20:                             <Setter TargetName="contentPopUp"
 21:                                     Property="Child" Value="{x:Null}"></Setter>
 22:                         </Trigger>
 23:
 24:                         <!-- Trigger for setting the content of expander when IsExpanded is true -->
 25:                         <Trigger SourceName="expanderHeader" Property="IsChecked" Value="True">
 26:                             <Setter TargetName="contentPopUp"
 27:                                     Property="Child" Value="{x:Null}"></Setter>
 28:                             <Setter TargetName="expanderContent"
 29:                                     Property="Content" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=OldContent,Mode=OneWay}"></Setter>
 30:                         </Trigger>
 31:                     </ControlTemplate.Triggers>

So this makes our code complete. But now as we have an option to configure the width and height of the popup. So the behavior of the popup should be something like this, It should zoom in / zoom out it self depending on the size of the content and the dimensions declared by the control user. Here comes the ViewBox wpf control. This control is made to do this. It adjusts its content according to the width/height of the viewbox. So what I will do is, I will make the content of expander as the content of a viewbox and will store this viewbox as the value of OldContent property. This will be done when the template is being applied to the control in OnApplyTemplate method. So I will override this method in our control class and store the content value.

  1: public override void OnApplyTemplate()
  2:         {
  3:             base.OnApplyTemplate();
  4:             object tmpContent = this.Content;
  5:             this.Content = null;
  6:
  7:             Viewbox containerViewBox = new Viewbox();
  8:             containerViewBox.Child = (UIElement)tmpContent;
  9:             OldContent = containerViewBox;
 10:         }

Complete source code is available here.

[PS: Please change the extension of file from .DOC to .ZIP]

Ha-P Coding 🙂

Posted in C#, WPF, XAML | Tagged: , , , | 2 Comments »

WPF 101 : A Simple Windows Explorer like Directory Browser

Posted by Manoj Garg on March 27, 2009

I just started learning about WPF. It is always good to learn something by developing some sample application which has something related to what you are learning.

One of my colleague suggested me to develop a Windows Explorer kind of file system explorer using WPF. something like as show in figure below

task

 

Requirements:

  1. It should have a left tree showing the directory tree rooted at “My Computer
  2. It should have a right pane showing all the children of the current node selected in the left side tree.
  3. Directories in the right side node should be navigable i.e. use can use the mouse double click or Enter key to see its contents. If user clicks on a directory then s/he should see the children of this directory and the left side tree should be in sync accordingly. Or, if user clicks on a file then that file should open in corresponding application.
  4. Only mode of handling the user event allowed is “DataBinding

My Approach:
First I will be using Model-View-ViewModel pattern for WPF
I will use WPF Treeview for left side directory Tree and a listbox for the right side pane for showing the children of the current selected node.

Model-View-ViewModel
This pattern is the most widely used and accepted approach for using in WPF application. This allows a developer to separate his logic with the presentation.
I will not go into the details of this design pattern. A detail description of it is available here by Josh Smith.
Following section discusses how I divided this sample app into these 3 logical parts.

Model:
We need a data source which provides us the information about current file system file like Logical Drives, Child Directories of a Directory or Files under a directory. I will be creating a class named FileSystemExplorerService which will serve as my interaction point for any information related to current file system. Below is the class diagram for this class

Model_ClassDiagram

View:
we will be need following views:

  1. View for Left Tree : File “View\FileSystemTree.xaml” contains this view.
  2. View for Right Pane : File “View\DirectoryViewer.xaml” contains this view.
  3. View for outer window: This view is for containing the above two views to act as an main window for the application. File “View\ExplorerWindow.xaml” contains this view.

ViewModel:
We will have separate viewmodel for each View in the application. Since all viewmodel need a notification mechanism, I will also be creating a base class from which all the view models will drive. Following are the classes in view model namespace.

  1. ViewModelBase class: This base class is responsible for handling the notification mechanism. It implements INotifyPropertyChanged interface. This is an abstract class.
  2. FileExplorerViewModel Class: this class is the Viewmodel for the left side tree.
  3. DirectoryViewerViewModel Class: This class is the viewmodel for the right side pane.
  4. ExplorerWindowViewModel Class: This class is the View model for the overall outer window.
  5. DirInfo Class: This class is the entity class which has information about a file/Directory like its name, path, children etc. we will be binding the Tree and the list box to a collection of DirInfo class.

Below is the class diagram for all the Viewmodel classes.

ViewModel_ClassDiagram

Implementation

Model Implementation

Following image shows the directory structure for the file explorer.

directorystructure

Lets start with the code for Model. Our model has just one class named “FileSystemExplorerService” which has three methods

  1. GetRootDirectories : This method returns the logical drives in the local file system.
  2. GetChildDirectories : This method returns the sub directories of the directory path passed.
  3. GetChildFiles : This method returns the files under the directory path passed.

Following is the code snipped for this class

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5: using System.IO;
   6: using System.Diagnostics;
   7:
   8: namespace FileExplorer.Model
   9: {
  10:     /// <summary>
  11:     /// Class to get file system information
  12:     /// </summary>
  13:     public class FileSystemExplorerService
  14:     {
  15:         /// <summary>
  16:         /// Gets the list of files in the directory Name passed
  17:         /// </summary>
  18:         /// <param name="directory">The Directory to get the files from</param>
  19:         /// <returns>Returns the List of File info for this directory.
  20:         /// Return null if an exception is raised</returns>
  21:         public static IList<FileInfo> GetChildFiles(string directory)
  22:         {
  23:             try
  24:             {
  25:                 return (from x in Directory.GetFiles(directory)
  26:                         select new FileInfo(x)).ToList();
  27:             }
  28:             catch (Exception e){
  29:                 Trace.WriteLine(e.Message);
  30:             }
  31:
  32:             return new List<FileInfo>();
  33:         }
  34:
  35:
  36:         /// <summary>
  37:         /// Gets the list of directories 
  38:         /// </summary>
  39:         /// <param name="directory">The Directory to get the files from</param>
  40:         /// <returns>Returns the List of directories info for this directory.
  41:         /// Return null if an exception is raised</returns>
  42:         public static IList<DirectoryInfo> GetChildDirectories(string directory)
  43:         {
  44:             try
  45:             {
  46:                 return (from x in Directory.GetDirectories(directory)
  47:                         select new DirectoryInfo(x)).ToList();
  48:             }
  49:             catch (Exception e)
  50:             {
  51:                 Trace.WriteLine(e.Message);
  52:             }
  53:
  54:             return new List<DirectoryInfo>();
  55:         }
  56:
  57:         /// <summary>
  58:         /// Gets the root directories of the system
  59:         /// </summary>
  60:         /// <returns>Return the list of root directories</returns>
  61:         public static IList<DriveInfo> GetRootDirectories()
  62:         {
  63:             return (from x in DriveInfo.GetDrives() select x).ToList();
  64:         }
  65:     }
  66: }

ViewModel Implementation

I have defined a custom class named DirInfo which contains the necessary information about a file/directory/logical drive in the system like name, path, type, size etc.

Thing to note in this class are two dependency properties named “IsExpanded” and “IsSelected”. These properties will be used when binding the DirInfo collection with the left tree view. IsExpanded tells the tree view that the current node in the tree should be in expanded state while IsSelected property tells the tree view that this node should be the selected node in the tree. To support the dependency properties DirInfo derives from DependencyObject class. Following code snipped shows the complete code this class.

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5: using System.Collections.ObjectModel;
   6: using System.IO;
   7: using FileExplorer.Properties;
   8: using System.Windows;
   9: using System.Collections;
  10:
  11:
  12: namespace FileExplorer.ViewModel
  13: {
  14:     /// <summary>
  15:     /// Enum to hold the Types of different file objects
  16:     /// </summary>
  17:     public enum ObjectType
  18:     {
  19:         MyComputer = 0,
  20:         DiskDrive = 1,
  21:         Directory = 2,
  22:         File = 3
  23:     }
  24:
  25:     /// <summary>
  26:     /// Class for containing the information about a Directory/File
  27:     /// </summary>
  28:     public class DirInfo : DependencyObject
  29:     {
  30:         #region // Public Properties
  31:         public string Name { get; set; }
  32:         public string Path { get; set; }
  33:         public string Root { get; set; }
  34:         public string Size { get; set; }
  35:         public string Ext { get; set; }
  36:         public int DirType { get; set; }
  37:         #endregion
  38:
  39:         #region // Dependency Properties
  40:         public static readonly DependencyProperty propertyChilds = DependencyProperty.Register("Childs", typeof(IList<DirInfo>), typeof(DirInfo));
  41:         public IList<DirInfo> SubDirectories
  42:         {
  43:             get { return (IList<DirInfo>)GetValue(propertyChilds); }
  44:             set { SetValue(propertyChilds, value); }
  45:         }
  46:
  47:         public static readonly DependencyProperty propertyIsExpanded = DependencyProperty.Register("IsExpanded", typeof(bool), typeof(DirInfo));
  48:         public bool IsExpanded
  49:         {
  50:             get { return (bool)GetValue(propertyIsExpanded); }
  51:             set { SetValue(propertyIsExpanded, value); }
  52:         }
  53:
  54:         public static readonly DependencyProperty propertyIsSelected = DependencyProperty.Register("IsSelected", typeof(bool), typeof(DirInfo));
  55:         public bool IsSelected
  56:         {
  57:             get { return (bool)GetValue(propertyIsSelected); }
  58:             set { SetValue(propertyIsSelected, value); }
  59:         }
  60:         #endregion
  61:
  62:         #region // .ctor(s)
  63:         public DirInfo()
  64:         {
  65:             SubDirectories = new List<DirInfo>();
  66:             SubDirectories.Add(new DirInfo("TempDir"));
  67:         }
  68:
  69:         public DirInfo(string directoryName)
  70:         {
  71:             Name = directoryName;
  72:         }
  73:
  74:         public DirInfo(DirectoryInfo dir)
  75:             : this()
  76:         {
  77:             Name = dir.Name;
  78:             Root = dir.Root.Name;
  79:             Path = dir.FullName;
  80:             DirType = (int)ObjectType.Directory;
  81:         }
  82:
  83:         public DirInfo(FileInfo fileobj)
  84:         {
  85:             Name = fileobj.Name;
  86:             Path = fileobj.FullName;
  87:             DirType = (int)ObjectType.File;
  88:             Size = (fileobj.Length / 1024).ToString() + " KB";
  89:             Ext = fileobj.Extension + " File";
  90:         }
  91:
  92:         public DirInfo(DriveInfo driveobj)
  93:             : this()
  94:         {
  95:             if (driveobj.Name.EndsWith(@"\"))
  96:                 Name = driveobj.Name.Substring(0, driveobj.Name.Length - 1);
  97:             else
  98:                 Name = driveobj.Name;
  99:
 100:             Path = driveobj.Name;
 101:             DirType = (int)ObjectType.DiskDrive;
 102:         }
 103:         #endregion
 104:     }
 105: }

Now lets start implementing the viewmodel for each of the views one by one.

Since all viewmodel will have properties which are change aware so these classes will have to implement INotifyPropertyChanged interface. To have this change notification at one place, I have created an abstract base class “ViewModelBase” for all the viewmodel. Following piece of code contains the implementation of this class.

   1: namespace FileExplorer.ViewModel
   2: {
   3:     public abstract class ViewModelBase : INotifyPropertyChanged
   4:     {
   5:         #region INotifyPropertyChanged Members
   6:
   7:         public event PropertyChangedEventHandler PropertyChanged;
   8:
   9:         /// <summary>
  10:         /// Raises the PropertyChanged event
  11:         /// </summary>
  12:         /// <param name="propertyName">The property name</param>
  13:         protected void OnPropertyChanged(string propertyName)
  14:         {
  15:             if (PropertyChanged != null)
  16:                 PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
  17:         }
  18:
  19:         #endregion
  20:
  21:         public ViewModelBase()
  22:         {
  23:         }
  24:     }
  25: }

Let’s start with the viewmodel for the main window view. I have created a class named “ExplorerWindowViewModel” to represent this view model. This class will be used as a datacontext for all the views. This class derives from ViewModelBase class. Following are some of the important members of this class.

  • CurrentDirectory: This is object of type DirInfo. This contains the currently selected item in the tree view.
  • ShowTreeView: This is a command that will be invoked to hide the left side tree view.
  • CurrentItems : Collection of DirInfo. Contains all the subdirectories and files of the CurrentDirectory
  • FileTreeVM: Object of FileTreeViewModel. Used to access members specific to the left pane view model.
  • DirViewVM: Object of DirectoryViewerViewModel. used to access members for the right side pane viewmodel

This class contains a method named “RefreshCurrentItems” which is called whenever the user changes the current directory either by selecting a node in tree view or going inside a directory through the right side pane. This method basically updates the CurrentItems property which is basically a collection of DirInfo objects, It contains the children of current directory both files and folders. Following is the code for this class.

   1: namespace FileExplorer.ViewModel
   2: {
   3:     public class ExplorerWindowViewModel : ViewModelBase
   4:     {
   5:         #region // Private Members
   6:         private DirInfo _currentDirectory;
   7:         private FileExplorerViewModel _fileTreeVM;
   8:         private DirectoryViewerViewModel _dirViewerVM;
   9:         private IList<DirInfo> _currentItems;
  10:         private bool _showDirectoryTree = true;
  11:         private ICommand _showTreeCommand;
  12:         #endregion
  13:
  14:         #region // .ctor
  15:         public ExplorerWindowViewModel()
  16:         {
  17:             FileTreeVM = new FileExplorerViewModel(this);
  18:             DirViewVM = new DirectoryViewerViewModel(this);
  19:             ShowTreeCommand = new RelayCommand(param => this.DirectoryTreeHideHandler());
  20:         }
  21:         #endregion
  22:
  23:         #region // Public Properties
  24:         /// <summary>
  25:         /// Name of the current directory user is in
  26:         /// </summary>
  27:         public DirInfo CurrentDirectory
  28:         {
  29:             get { return _currentDirectory; }
  30:             set
  31:             {
  32:                 _currentDirectory = value;
  33:                 RefreshCurrentItems();
  34:                 OnPropertyChanged("CurrentDirectory");
  35:             }
  36:         }
  37:
  38:         /// <summary>
  39:         /// Tree View model
  40:         /// </summary>
  41:         public FileExplorerViewModel FileTreeVM
  42:         {
  43:             get { return _fileTreeVM; }
  44:             set
  45:             {
  46:                 _fileTreeVM = value;
  47:                 OnPropertyChanged("FileTreeVM");
  48:             }
  49:         }
  50:
  51:
  52:         /// <summary>
  53:         /// Visibility of the 
  54:         /// </summary>
  55:         public bool ShowDirectoryTree
  56:         {
  57:             get { return _showDirectoryTree; }
  58:             set
  59:             {
  60:                 _showDirectoryTree = value;
  61:                 OnPropertyChanged("ShowDirectoryTree");
  62:             }
  63:         }
  64:
  65:
  66:         /// <summary>
  67:         /// 
  68:         /// </summary>
  69:         public ICommand ShowTreeCommand
  70:         {
  71:             get { return _showTreeCommand; }
  72:             set
  73:             {
  74:                 _showTreeCommand = value;
  75:                 OnPropertyChanged("ShowTreeCommand");
  76:             }
  77:         }
  78:
  79:         /// <summary>
  80:         /// Tree View model
  81:         /// </summary>
  82:         public DirectoryViewerViewModel DirViewVM
  83:         {
  84:             get { return _dirViewerVM; }
  85:             set
  86:             {
  87:                 _dirViewerVM = value;
  88:                 OnPropertyChanged("DirViewVM");
  89:             }
  90:         }
  91:
  92:         /// <summary>
  93:         /// Children of the current directory to show in the right pane
  94:         /// </summary>
  95:         public IList<DirInfo> CurrentItems
  96:         {
  97:             get
  98:             {
  99:                 if (_currentItems == null)
 100:                 {
 101:                     _currentItems = new List<DirInfo>();
 102:                 }
 103:                 return _currentItems;
 104:             }
 105:             set
 106:             {
 107:                 _currentItems = value;
 108:                 OnPropertyChanged("CurrentItems");
 109:             }
 110:         }
 111:         #endregion
 112:
 113:         #region // methods
 114:         private void DirectoryTreeHideHandler()
 115:         {
 116:             ShowDirectoryTree = false;
 117:         }
 118:
 119:         /// <summary>
 120:         /// this method gets the children of current directory and stores them in the CurrentItems Observable collection
 121:         /// </summary>
 122:         protected void RefreshCurrentItems()
 123:         {
 124:             IList<DirInfo> childDirList = new List<DirInfo>();
 125:             IList<DirInfo> childFileList = new List<DirInfo>();
 126:
 127:             //If current directory is "My computer" then get the all logical drives in the system
 128:             if (CurrentDirectory.Name.Equals(Resources.My_Computer_String))
 129:             {
 130:                 childDirList = (from rd in FileSystemExplorerService.GetRootDirectories()
 131:                                 select new DirInfo(rd)).ToList();
 132:             }
 133:             else
 134:             {
 135:                 //Combine all the subdirectories and files of the current directory
 136:                 childDirList = (from dir in FileSystemExplorerService.GetChildDirectories(CurrentDirectory.Path)
 137:                                 select new DirInfo(dir)).ToList();
 138:
 139:                 childFileList = (from fobj in FileSystemExplorerService.GetChildFiles(CurrentDirectory.Path)
 140:                                  select new DirInfo(fobj)).ToList();
 141:
 142:                 childDirList = childDirList.Concat(childFileList).ToList();
 143:             }
 144:
 145:             CurrentItems = childDirList;
 146:         }
 147:         #endregion
 148:     }
 149: }

Now lets talk about tree viewmodel. This is defined in a class named “FileExplorerViewModel”. This viewmodel contains a property SystemDirectorySource which is list of root nodes in the tree. Right now, I am adding only My Computer node to it. This class has a method ExpandToCurrentNode which sets the IsExpanded property of the CurrentItem to true if this is also the selected item in right side pane. Following is the code for this class.

   1:
   2: namespace FileExplorer.ViewModel
   3: {
   4:     public class FileExplorerViewModel : ViewModelBase
   5:     {
   6:         #region // Private fields
   7:         private ExplorerWindowViewModel _evm;
   8:         private DirInfo _currentTreeItem;
   9:         private IList<DirInfo> _sysDirSource;
  10:         #endregion
  11:
  12:         #region // Public properties
  13:         /// <summary>
  14:         /// list of the directories 
  15:         /// </summary>
  16:         public IList<DirInfo> SystemDirectorySource
  17:         {
  18:             get { return _sysDirSource; }
  19:             set
  20:             {
  21:                 _sysDirSource = value;
  22:                 OnPropertyChanged("SystemDirectorySource");
  23:             }
  24:         }
  25:
  26:         /// <summary>
  27:         /// Current selected item in the tree
  28:         /// </summary>
  29:         public DirInfo CurrentTreeItem
  30:         {
  31:             get { return _currentTreeItem; }
  32:             set
  33:             {
  34:                 _currentTreeItem = value;
  35:                 _evm.CurrentDirectory = _currentTreeItem;
  36:             }
  37:         }
  38:         #endregion
  39:
  40:         #region // .ctor
  41:         /// <summary>
  42:         /// ctor
  43:         /// </summary>
  44:         /// <param name="evm"></param>
  45:         public FileExplorerViewModel(ExplorerWindowViewModel evm)
  46:         {
  47:             _evm = evm;
  48:
  49:             //create a node for "my computer"
  50:             // this will be the root for the file system tree
  51:             DirInfo rootNode = new DirInfo(Resources.My_Computer_String);
  52:             rootNode.Path = Resources.My_Computer_String;
  53:             _evm.CurrentDirectory = rootNode; //make root node as the current directory
  54:
  55:             SystemDirectorySource = new List<DirInfo> { rootNode };
  56:         }
  57:         #endregion
  58:
  59:         #region // public methods
  60:         /// <summary>
  61:         /// 
  62:         /// </summary>
  63:         /// <param name="curDir"></param>
  64:         public void ExpandToCurrentNode(DirInfo curDir)
  65:         {
  66:             //expand the current selected node in tree 
  67:             //if this is an ancestor of the directory we want to navigate or "My Computer" current node 
  68:             if (CurrentTreeItem != null && (curDir.Path.Contains(CurrentTreeItem.Path) || CurrentTreeItem.Path == Resources.My_Computer_String))
  69:             {
  70:                 // expand the current node
  71:                 // If the current node is already expanded then first collapse it n then expand it
  72:                 CurrentTreeItem.IsExpanded = false;
  73:                 CurrentTreeItem.IsExpanded = true;
  74:             }
  75:         }
  76:         #endregion
  77:     }
  78: }

finally lets talk about viewmodel for right side pane. This viewmodel is defined in DirectoryViewerViewModel class. Main responsibility of this viewmodel is to keep track of the current directory user is moving to and processing the user event once user invokes the action for opening the currently selected item in the pane by either double clicking or by pressing keyboard Enter key.

I am maintaining the currently selected item in an property named CurrentItem. This is a simple C# property which the view will update accordingly as the selection in view changes. To handle the user event, I have a method named OpenCurrentObject(). This method depending on the object type performs the desired operation i.e. if this is a file then it uses System.Diagnostics.Process.Start method to open that file or if the current object is a directory then it shows its child and updates the tree view accordingly using the ExpandToCurrentNode method of the FileExplorerViewModel. Following piece of code contains the implementation for this class.

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5: using System.Windows;
   6: using System.Windows.Controls;
   7: using System.Windows.Input;
   8: using FileExplorer.Model;
   9:
  10: namespace FileExplorer.ViewModel
  11: {
  12:     /// <summary>
  13:     /// View model for the right side pane
  14:     /// </summary>
  15:     public class DirectoryViewerViewModel : ViewModelBase
  16:     {
  17:         #region // Private variables
  18:         private ExplorerWindowViewModel _evm;
  19:         private DirInfo _currentItem;
  20:         #endregion
  21:
  22:         #region // .ctor
  23:         public DirectoryViewerViewModel(ExplorerWindowViewModel evm)
  24:         {
  25:             _evm = evm;
  26:         }
  27:         #endregion
  28:
  29:         #region // Public members
  30:         /// <summary>
  31:         /// Indicates the current directory in the Directory view pane
  32:         /// </summary>
  33:         public DirInfo CurrentItem
  34:         {
  35:             get { return _currentItem; }
  36:             set { _currentItem = value; }
  37:         }
  38:         #endregion
  39:
  40:         #region // Public Methods
  41:         /// <summary>
  42:         /// processes the current object. If this is a file then open it or if it is a directory then return its subdirectories
  43:         /// </summary>
  44:         public void OpenCurrentObject()
  45:         {
  46:             int objType = CurrentItem.DirType; //Dir/File type
  47:
  48:             if ((ObjectType)CurrentItem.DirType == ObjectType.File)
  49:             {
  50:                 System.Diagnostics.Process.Start(CurrentItem.Path);
  51:             }
  52:             else
  53:             {
  54:                 _evm.CurrentDirectory = CurrentItem;
  55:                 _evm.FileTreeVM.ExpandToCurrentNode(_evm.CurrentDirectory);
  56:             }
  57:         }
  58:         #endregion
  59:     }
  60: }

View Implementation

Lets start with the implementation of view for directory tree in the left pane. Implementation for this is simple. I have a tree view whose itemsource property is set to SystemDirectorySource property of the FileTreeViewModel class. Then I have a HierarchicalDataTemplate whose target type is DirInfo so whenever an object of type DirInfo is bound to the tree this template will get applied to it. While binding to the DirInfo object I am using a converter which basically converts the DirInfo object into a List of DirInfo object whose content are the child directories of the directory represented by DirInfo object. Following code snippet contains code for this converter.

   1: public class GetFileSysemInformationConverter : IValueConverter
   2:    {
   3:        #region IValueConverter Members
   4:
   5:        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
   6:        {
   7:            try {
   8:                DirInfo nodeToExpand = value as DirInfo;
   9:                if (nodeToExpand == null)
  10:                    return null;
  11:
  12:                 //return the subdirectories of the Current Node
  13:                 if ((ObjectType)nodeToExpand.DirType == ObjectType.MyComputer)
  14:                 {
  15:                     return (from sd in FileSystemExplorerService.GetRootDirectories()
  16:                                     select new DirInfo(sd)).ToList();
  17:                 }
  18:                 else
  19:                 {
  20:                     return (from dirs in FileSystemExplorerService.GetChildDirectories(nodeToExpand.Path)
  21:                             select new DirInfo(dirs)).ToList();
  22:                 }
  23:
  24:            }
  25:            catch { return null; }
  26:        }
  27:
  28:        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  29:        {
  30:            throw new NotImplementedException();
  31:        }
  32:
  33:        #endregion
  34:    }

In this view I am also defining a style which applies to TreeViewItems. This style binds the IsExpanded and IsSelected properties of DirInfo object to a node in the tree. I am also assigning an event handler for the Expanded event of a node in tree. Following XAML code shows the hierarchical data template and Style for TreeViewItem.

   1: <local:GetFileSysemInformationConverter x:Key="getFileSysemInformationConverter"/>
   2:
   3:         <HierarchicalDataTemplate DataType="{x:Type local:DirInfo}"
   4:                                   ItemsSource="{Binding Converter={StaticResource getFileSysemInformationConverter}}">
   5:             <StackPanel Orientation="Horizontal">
   6:                 <Image Width="20" Height="20" Stretch="Fill" x:Name="img" />
   7:                 <TextBlock Text="{Binding Name}" Margin="5,0,0,0" />
   8:             </StackPanel>
   9:             <HierarchicalDataTemplate.Triggers>
  10:                 <DataTrigger Binding="{Binding Path=DirType}" Value="0">
  11:                     <Setter Property="Image.Source" TargetName="img" Value="/Images/MyComputer.jpg"></Setter>
  12:                 </DataTrigger>
  13:                 <DataTrigger Binding="{Binding Path=DirType}" Value="1">
  14:                     <Setter Property="Image.Source" TargetName="img" Value="/Images/diskdrive.png"></Setter>
  15:                 </DataTrigger>
  16:                 <DataTrigger Binding="{Binding Path=DirType}" Value="2">
  17:                     <Setter Property="Image.Source" TargetName="img" Value="/Images/folder.png"></Setter>
  18:                 </DataTrigger>
  19:             </HierarchicalDataTemplate.Triggers>
  20:         </HierarchicalDataTemplate>
  21:
  22:         <Style TargetType="TreeViewItem">
  23:             <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
  24:             <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
  25:             <EventSetter Event="Expanded" Handler="TreeView_Expanded"></EventSetter>
  26:         </Style>

While developing this I was facing issue in syncing the right side pane with the tree view. To fix this I used the TreeNode expanded method. In this method I check all the direct children of the node to search for the the child with the name equal to the CurrentDirectory value. If found, Expand this node. Following is the code for the Expanded method.

 

   1: private void TreeView_Expanded(object sender, RoutedEventArgs e)
   2:         {
   3:             TreeViewItem currentTreeNode = sender as TreeViewItem;
   4:             if (currentTreeNode == null)
   5:                 return;
   6:  
   7:             if (currentTreeNode.ItemsSource == null)
   8:                 return;
   9:  
  10:             DirInfo parentDirectory = currentTreeNode.Header as DirInfo;
  11:             if (parentDirectory == null)
  12:                 return;
  13:  
  14:             foreach (DirInfo d in currentTreeNode.ItemsSource)
  15:             {
  16:                 if (myViewModel.CurrentDirectory.Path.Equals(d.Path))
  17:                 {
  18:                     d.IsSelected = true;
  19:                     d.IsExpanded = true;
  20:                     break;
  21:                 }
  22:             }
  23:             e.Handled = true;
  24:         } 

To sync the currently selected node in the tree view with CurrentItem property of the the FileTreeViewModel, first I was planning to do a simple two way binding between the viewmodel property and the treeview’s SelectedItem property. But while doing this I came to know (I am still learning the concepts :)) that since SelectedItem is a readonly property so I can only read from it, can’t assign a binding to it even in the OneWayToSource mode. So I hooked to the selectedItemChanged event of the tree view and in the code behind I assigned the selectedItem property to the currentItem property as follows.

   1: private void DirectoryTree_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
   2: {
   3:      myViewModel.FileTreeVM.CurrentTreeItem = DirectoryTree.SelectedItem as DirInfo;
   4: }

Now lets see the implementation for right side pane i.e. where we show the children of a directory. I am using a Listbox to display the child directories and files. This list box’s ItemSource is set to the CurrentItems property of the ExplorerWindowViewModel. since we want to show the items of the list box wrapped according to the width of the explorer window so I am using WrapPanel control as the ItemsPanelTemplate for this listbox.

   1: <ListBox x:Name="dirList"  
   2:                  ItemsSource="{Binding Path=CurrentItems}" 
   3:                  ItemTemplate="{StaticResource DirViewTemplate}" BorderThickness="0" 
   4:                  HorizontalContentAlignment="Left" VerticalContentAlignment="Top" 
   5:                  Grid.Column="0" Grid.Row="0" 
   6:                  ScrollViewer.HorizontalScrollBarVisibility="Disabled"
   7:                  SelectedItem="{Binding Path=DirViewVM.CurrentItem,Mode=OneWayToSource}"
   8:                  MouseDoubleClick="dirList_MouseDoubleClick"
   9:                  KeyDown="dirList_KeyDown">
  10:             <ListBox.ItemsPanel>
  11:                 <ItemsPanelTemplate>
  12:                     <WrapPanel Orientation="Horizontal" ItemWidth="220"></WrapPanel>
  13:                 </ItemsPanelTemplate>
  14:             </ListBox.ItemsPanel>
  15:         </ListBox>

Each listboxitem represents a directory or a file. Each object will have a image, a name, type whether a FileFolder or a extention of that file and Size of the file. So I have defined an DataTemplate for each of the list box item as follows

   1: <!-- Data template for displaying a directory or a file -->
   2:         <DataTemplate x:Key="DirViewTemplate">
   3:             <Label HorizontalAlignment="Left" 
   4:                    Background="Transparent" 
   5:                    DataContext="{Binding}"
   6:                    IsTabStop="True" BorderThickness="1" >
   7:                 <Label.Content>
   8:                     <DockPanel>
   9:                         <Image DockPanel.Dock="Left" VerticalAlignment="Center"
  10:                                x:Name="img" 
  11:                                Margin="5" 
  12:                                Width="50" Height="50" />
  13:                         <StackPanel DockPanel.Dock="Left" 
  14:                                     VerticalAlignment="Center" HorizontalAlignment="Left" 
  15:                                     x:Name="ObjInfoPanel"> 
  16:                             <TextBlock x:Name="ObjName"
  17:                                        FontWeight="Bold" 
  18:                                        Text="{Binding Name}" 
  19:                                        Style="{StaticResource NormalTextBlockStyle}"/>
  20:                             <TextBlock x:Name="ObjType"
  21:                                        Style="{StaticResource FadedTextBlockStyle}"/>
  22:                             <TextBlock x:Name="ObjSize"
  23:                                        HorizontalAlignment="Left"
  24:                                        Style="{StaticResource FadedTextBlockStyle}"/>
  25:                         </StackPanel>
  26:                     </DockPanel>
  27:                 </Label.Content>
  28:                 <Label.ToolTip>
  29:                     <ToolTip Name="FileInfo" Placement="Mouse">
  30:                         <TextBlock Text="{Binding Name}"/>
  31:                     </ToolTip>
  32:                 </Label.ToolTip>
  33:             </Label>
  34:             
  35:              <DataTemplate.Triggers>
  36:                 <DataTrigger Binding="{Binding Path=DirType}" Value="0">
  37:                     <Setter Property="Image.Source" TargetName="img" Value="/Images/MyComputer.jpg"></Setter>
  38:                 </DataTrigger>
  39:                 <DataTrigger Binding="{Binding Path=DirType}" Value="1">
  40:                     <Setter Property="Image.Source" TargetName="img" Value="/Images/diskdrive.png"></Setter>
  41:                 </DataTrigger>
  42:                 <DataTrigger Binding="{Binding Path=DirType}" Value="2">
  43:                     <Setter Property="Image.Source" TargetName="img" Value="/Images/folder.png"></Setter>
  44:                     <Setter Property="Text" TargetName="ObjType" Value="File Folder"></Setter>
  45:                 </DataTrigger>
  46:                 <DataTrigger Binding="{Binding Path=DirType}" Value="3">
  47:                     <Setter Property="Image.Source" TargetName="img" Value="/Images/file.png"></Setter>
  48:                     <Setter Property="Text" TargetName="ObjType" Value="{Binding Ext}"></Setter>
  49:                     <Setter Property="Visibility" TargetName="ObjSize" Value="Visible"></Setter>
  50:                     <Setter Property="Text" TargetName="ObjSize" Value="{Binding Size}"></Setter>
  51:                 </DataTrigger>
  52:                  <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type ListBoxItem}},Path=IsSelected}" Value="True" >
  53:                      <Setter Property="Background" TargetName="ObjInfoPanel" Value="Gray" ></Setter>
  54:                      <!--<Setter Property="Foreground" TargetName="ObjName" Value="Gray" ></Setter>-->
  55:                      <Setter Property="Foreground" TargetName="ObjType" Value="Black" ></Setter>
  56:                      <Setter Property="Foreground" TargetName="ObjSize" Value="Black" ></Setter>
  57:                 </DataTrigger>
  58:             </DataTemplate.Triggers>
  59:         </DataTemplate>    

 

Like the actual windows explorer, I also wanted to have the properties of a folder or a file to be shown in a different color like its type/ext or size in a dimmed or grayish color. Similarly, when file/folder name is larger then the width of the text block then trim it. So I defined two styles targeting the TextBlock control.

   1: <!-- Style for folder/file name text block -->
   2: <Style x:Key="NormalTextBlockStyle">
   3:             <!--<Setter Property="TextBlock.Width" Value="120"></Setter>-->
   4:             <Setter Property="TextBlock.TextWrapping" Value="NoWrap"></Setter>
   5:             <Setter Property="TextBlock.TextTrimming" Value="CharacterEllipsis"></Setter>
   6:             <Setter Property="TextBlock.VerticalAlignment" Value="Center"></Setter>
   7:         </Style>
   8:         
   9:         <!-- Style for folder/file type and size text block -->
  10:         <Style x:Key="FadedTextBlockStyle" BasedOn="{StaticResource NormalTextBlockStyle}">
  11:             <Setter Property="TextBlock.Foreground" Value="DimGray"></Setter>
  12:         </Style>

WPF provides an excellent support for trimming the content of a text block. It has a property TextTrimming which when set to value CharacterEllipsis along with TextWrapping set to value NoWrap , It automatically trims the content of the text box. All the text blocks in the style will have the same properties except the foreground color of the text. So I defined the style FadedTextBlockStyle which inherits the value for some styling from the NormalTextBlockStyle using the BasedOn attribute. This inheritance is similar to OOPS inheritance.

Now since we are using listbox for the item container, whenever an item is selected from the list it applies its default style to it i.e. it grays out the background of the list item. which is not what happens in windows file explorer, it grays only the folder name and its property text. So as every beginner would do, I wrote a style targeting the TreeViewItem which has a trigger waiting to fire whenever the tree view item is selected and when it fires it goes and changes the background of the treeviewitem to transparent. But it didn’t work. I should not actually since the background color of the selected items is controlled by HighlightBrush. So after little searching found out this style which sets the background of the treeviewitem to transparent.

   1: <Style TargetType="ListBoxItem">
   2:     <Style.Resources>
   3:          <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent"/>
   4:          <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Transparent"/>
   5:     </Style.Resources>
   6: </Style>

Now use these above two user controls to make outer window UI. This one is simple, It has a grid with three columns. First column has the treeview, second column has the gridsplitter and the third column has the directoryviewer view.

To set the dataContext right, I overridden the OnStartUp method of the App.XAML. In this method, I created an object of ExplorerWindowViewModel and assigned it as the data context for the Outer window.

   1: protected override void OnStartup(StartupEventArgs e)
   2:        {
   3:            base.OnStartup(e);
   4:  
   5:            ExplorerWindow window = new ExplorerWindow();
   6:  
   7:            // ViewModel to bind the main window 
   8:            ExplorerWindowViewModel viewModel = new ExplorerWindowViewModel();
   9:  
  10:            // Allow all controls in the window to bind to the ViewModel by setting the 
  11:            // DataContext, which propagates down the element tree.
  12:            window.DataContext = viewModel;
  13:  
  14:            window.Show();
  15:        }

 

Complete source code is available here. Please remove  .doc from file . This is due to restriction from wordpress to not allow zip files as uploads.

So this makes the complete file explorer with all the requirements we started with in start met. But still it has lots of scope for improvement.

Please drop in your suggestions. As I am still learning nuances of WPF. your comments might help me in my this quest.

Stay tuned for more WPF 101 coming …… 🙂

Posted in .Net 3.5, WPF, XAML | Tagged: , , , , | 40 Comments »

India v/s India

Posted by Manoj Garg on March 20, 2009

This is the transcript of the last year’s Lead India campaign by TOI.

  india

“There are two Indias in this country.

One India is straining at the leash, eager to spring forth and live up to all the adjectives that the world has been showering recently upon us.

The other India is the leash.

One India says, give me a chance and I’ll prove myself. The other India says, prove yourself first and maybe then you’ll have a chance.

One India lives in the optimism of our heart. The other India lurks in the skepticism of our minds.

One India wants. The other India hopes.

One India leads. The other India follows.

But conversions are on the rise. With each passing day more and more people from other India have been coming over to this side. And quietly, while the world is not looking, a pulsating, dynamic new India is emerging.

sport-graphics-2007_709046aAn India whose faith in success is far greater then its fear of failure. An India that no longer boycotts foreign-made goods but buys out the companies that make them instead.

History, they say, is a bad motorist. It rarely signals its intentions when it is taking a turn.

This is that rarely-ever moment. History is turning a page.

For more then half a century, our nation has sprung, stumbled, run fallen, rolled over, got up, dusted herself and cantered, sometimes lurched on. But today, as we begin our 60th year as a free nation, the ride has brought us to the edge of time’s great precipice.

And one India – a tiny little voice at the back of the head – looking down at the bottom of the ravine and hesitating.

The other India is looking up at the sky and saying, it’s time to fly.”

 

Posted in India, Non Technical | Tagged: , | Leave a Comment »

Accessing Strings from Resource File in XAML markup

Posted by Manoj Garg on March 18, 2009

Its a good practice to have constant strings in Resource files i.e. files with .Resx extensions.

Accessing the resource files in Code behind is straight forward. syntax is pretty simple

<<Resource File Name>>.<<String Key in the resource file>>

For example if your resource file name is “Strings.Resx” and the string key is “My_Const_String”. To access this value in code behind you can write “Strings.My_Const_String” and this will give you the key value defined in the resource file. But what if, you want to access this resource string in XAML file only.

This may be very basic stuff but as I am ramping myself in WPF, I had tough time finding a way to do it. After 30 odd minutes of googling found a way here. So thought of writing it on my blog.

Accessing the resource string is a thee step process.

  1. Make the resource strings Public: By default the resource strings are internal. so if we want to use then in XAML we need to change their modifier to public. To do this just open the resource file and change the value of “Access Modifier” drop down to public from internal. Following image show a snapshot of this in VS 2008

resource 

    2.   Register the namespace with the xmlns

E.g. Suppose you are default resource file, created with WPF project, Resources.Resx in the Properties folder of your project. Then use the following syntax to register your namespace.

   1: xmlns:const="clr-namespace:FileExplorer.Properties"

 

   3.   Use x:Static to access to static resource strings since all the strings stored in a resource file are static properties of that resource class.

E.g Now you have a String named “Window_Title_String” and if you want to set the title of the current window to this string. you can use the following code snippet

   1: <Window x:Class="SampleProj.View"
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:     xmlns:const="clr-namespace:SampleProj.Properties"
   5:     Title="{x:Static const:Resources.Window_Title_String}"
   6: >

 

Hope it helps.

Ha-P Binding 🙂

Posted in .Net 3.5, WPF, XAML | Tagged: , , | 9 Comments »

Kalam: The Great Visionary

Posted by Manoj Garg on March 13, 2009

Received a forwarded email.  n Just couldn’t stop myself from pinning it down here:

Kalam’s words came true ………
Kalam: INDIA will become a Superpower in 2020

Dhoni’s Blue boys did it 🙂

1437485808_3f8af751f1

lols 🙂

Posted in Cricket Fun | Leave a Comment »