Pages

Wednesday, June 20, 2012

Hierarchical DataBinding in TreeView using MVVM pattern

I am now going to show the interesting work in MVVM pattern that Hierarchical DataBinding in WPF. Basically we will do the Hierarchical DataBinding for the ItemsControl where Items also will be having the ItemsControl as the base classes.

There are more number of Hierarchical data controls are there in wpf like TreeView and Menu control. But here i am going to show the sample using TreeView.

My TreeView should be looking like this when we ran the application

Document1
     Course1
             Bookno-1
             Bookno-2
Document2
     Course 2
             Book no-1
             Book no-2


public class ViewModelBase :INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged(string propname)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propname));
        }
    }
}

Model classes in this application will inherit the ViewModelBase class to notify the property changes to the UI. Whenever the property changes in the Model classes will be notified through the ViewModelBase to the UI.



public class Book : ViewModelBase
{
     private string bookname = string.Empty;

     public string BookName
     {
         get
         {
             return bookname;
         }
         set
         {
             bookname = value;
             OnPropertyChanged("BookName");
         }
     }

     public Book(string bookname)
     {
         BookName = bookname;
     }
}


The same way other classes are ...
public class Department : ViewModelBase
{
    private List<Course> courses;

    public Department(string depname)
    {
        DepartmentName = depname;
        Courses = new List<Course>()
        {
            new Course("Course1"),
            new Course("Course2")
        };
    }

    public List<Course> Courses
    {
        get
        {
            return courses;
        }
        set
        {
            courses = value;
            OnPropertyChanged("Courses");
        }
    }

    public string DepartmentName
    {
        get;
        set;
    }
}

public class Course :ViewModelBase
{
    private List<Book> books;

    public Course(string coursename)
    {
        CourseName = coursename;
        Books = new List<Book>()
        {
            new Book("JJJJ"),
            new Book("KKKK"),
            new Book("OOOOO")
        };
    }

    public List<Book> Books
    {
        get
        {
            return books;
        }
        set
        {
            books = value;
            OnPropertyChanged("Books");
        }
    }

    public string CourseName
    {
        get;
        set;
    }
}

Finally the DataContext of the TreeView will be TreeViewModel which will be having the Items of the TreeView which is going to be bound.


public class TreeViewModel :ViewModelBase
{
    private List<Department> departments;

    public TreeViewModel()
    {
        Departments = new List<Department>()
        {
            new Department("Department1"),
            new Department("Department2")
        };
    }

    public List<Department> Departments
    {
        get
        {
            return departments;
        }
        set
        {
            departments = value;
            OnPropertyChanged("Departments");
        }
    }
}

The above ViewModel class will be set as a DataContext for TreeView and finally it will display the Hierarchical items based on the below xaml code.


<Window x:Class="TestApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:this="clr-namespace:TestApp"
        Title="MainWindow" Height="350" Width="525">

    <Window.DataContext>
        <this:TreeViewModel />
    </Window.DataContext>

    <Window.Resources>
        <HierarchicalDataTemplate ItemsSource="{Binding Courses}" DataType="{x:Type this:Department}">
            <Label Content="{Binding DepartmentName}"/>
        </HierarchicalDataTemplate>

        <HierarchicalDataTemplate ItemsSource="{Binding Books}" DataType="{x:Type this:Course}">
            <Label Content="{Binding CourseName}"/>
        </HierarchicalDataTemplate>

        <DataTemplate DataType="{x:Type this:Book}">
            <Label Content="{Binding BookName}"/>
        </DataTemplate>

    </Window.Resources>

    <Grid>
        <TreeView ItemsSource="{Binding Departments}">

        </TreeView>
    </Grid>
</Window>

The HierarchicalDataTemplate has the ItemsSource property to bind the sub level of items to the VisualTree.. It will be helpful to bind 'n' level of sub items into the nested level...


You can find the solution in the below link.


Monday, May 21, 2012

MVVM sample using DataGrid control in WPF


Here is my first MVVM sample in WPF. I have prepared the sample using MVVM with the help of DataGrid in WPF.
The following sample will just showcase the information about the person in the MVVM pattern.


RecordInfo :- [ Model ]
Basically model will have only the data information. Model does not know anything about the ViewModel. It will just build the View through ViewModel.
It will have the following datas. Name, Age, DateOfBirth and Address.


 public class RecordInfo : ViewModelBase 
 {        
     string _name = string.Empty;        
     Int32 _age = 0;        
     DateTime _dob;        
     string _address = string.Empty;

     public RecordInfo()        
     {
                    
     }

     public string Name
     {
         get
         {
            return _name;  
         }
         set            
         {
            _name = value;
            OnPropertyChanged("Name");
         }
     }
     
     public Int32 Age
     {
         get  
         {  
            return _age;  
         }
         set 
         { 
            _age = value;  
            OnPropertyChanged("Age");
         } 
     }

     public DateTime DateOfBirth        
     {            
         get            
         {                
             return _dob;            
         }            
         set            
         {                
             _dob = value;                
             OnPropertyChanged("DateOfBirth");            
         }        
     }

     public string Address        
     {            
          get            
          {                
              return _address;            
          }            
          set            
          {                
              _address = value;                
              OnPropertyChanged("Address");            
          }        
     } 
 }

ViewModelBase :-

Both ViewModel and Model will have the ViewModelBase as the base class. ViewModelBase is nothing but the class will just notify property changes to the View through the INotifyPropertyChanged interface. Instead of inheriting the INotifyPropertyChanged interface to both ViewModel and Model. It has been used only in the ViewModelBase.

One interesting aspect of ViewModelBase is that it provides the ability to verify that a property with a given name actually exists on the ViewModel object. The below code adds this useful support to MVVM.


public class ViewModelBase : INotifyPropertyChanged 
{        
       public ViewModelBase()        
       {

       }
       public void OnPropertyChanged(string name)        
       {            
            if (PropertyChanged != null)            
            {                
                 PropertyChanged(thisnew PropertyChangedEventArgs(name));            
            }        
       }
       public event PropertyChangedEventHandler PropertyChanged;  
}

DataGridViewModel : [ ViewModel ]

ViewModel will have the observablecollection of elements to update the View with the Model class.  It always serves the data binding between View and Model. That means ViewMode acts as a DataBinder or Converter to communicate the information between View to Model through public properties and Delegate commands. As this class class is separated from the View (UI), these classes are relatively straightforward to unit tests.

public class DataGridViewModel : ViewModelBase
        {
            ObservableCollection<RecordInfo> infos;
            ICommand _command;
 
            public DataGridViewModel()
            {
                PersonsInfo = new ObservableCollection<RecordInfo>();
                PersonsInfo.Add(new RecordInfo
                {
                    Name = "AA",
                    Age = 24,
                    DateOfBirth = new DateTime(1987, 4, 29),
                    Address = "XXX XXX XXXX"
                });
                PersonsInfo.Add(new RecordInfo
                {
                    Name = "BB",
                    Age = 23,
                    DateOfBirth = new DateTime(1988, 3, 4),
                    Address = "XXX XXXXX XXX"
                });
                PersonsInfo.Add(new RecordInfo
                {
                    Name = "CC",
                    Age = 26,
                    DateOfBirth = new DateTime(1985, 10, 2),
                    Address = "XXX XXX X"
                });
                PersonsInfo.Add(new RecordInfo
                {
                    Name = "DD",
                    Age = 28,
                    DateOfBirth = new DateTime(1983, 5, 7),
                    Address = "XX XXXXX XX"
                });
                PersonsInfo.Add(new RecordInfo
                {
                    Name = "EE",
                    Age = 26,
                    DateOfBirth = new DateTime(1985, 11, 20),
                    Address = "XXXX XXXXX XXX"
                });
                PersonsInfo.Add(new RecordInfo
                {
                    Name = "FF",
                    Age = 22,
                    DateOfBirth = new DateTime(1989, 1, 27),
                    Address = "XXXXXXXXXXX XX"
                });
                PersonsInfo.Add(new RecordInfo
                {
                    Name = "GG",
                    Age = 21,
                    DateOfBirth = new DateTime(1990, 8, 6),
                    Address = "XXX XXXX XXXXXX"
                });
                PersonsInfo.Add(new RecordInfo
                {
                    Name = "HH",
                    Age = 23,
                    DateOfBirth = new DateTime(1988, 9, 9),
                    Address = "XX XXXXXXXXX XXX"
                });
                PersonsInfo.Add(new RecordInfo
                {
                    Name = "II",
                    Age = 24,
                    DateOfBirth = new DateTime(1987, 10, 18),
                    Address = "XXXXXXXXX XXXX"
                });
                PersonsInfo.Add(new RecordInfo
                {
                    Name = "JJ",
                    Age = 21,
                    DateOfBirth = new DateTime(1990, 11, 27),
                    Address = "XXXXX XXXXXXXX XX"
                });
            }
 
            public ObservableCollection<RecordInfo> PersonsInfo
            {
                get
                {
                    return infos;
                }
                set
                {
                    infos = value;
                    OnPropertyChanged("PersonsInfo");
                }
            }
 
            public ICommand RemoveCommand
            {
                get
                {
                    if (_command == null)
                    {
                        _command = new DelegateCommand(CanExecute, Execute);
                    }
                    return _command;
                }
            }
 
            private void Execute(object parameter)
            {
                int index = PersonsInfo.IndexOf(parameter as RecordInfo);
                if (index > -1 && index < PersonsInfo.Count)
                {
                    PersonsInfo.RemoveAt(index);
                }
            }
 
            private bool CanExecute(object parameter)
            {
                return true;
            }
        }
 
The above class contains the ObservableCollection of Model class which relatively updates the view with the respective information.

DelegateCommand:-

It enables the user to hook up UI interactions with code without tightly coupling with two. The controls in the UI aren’t intimately aware of the command logic they are connected with, and the command logic is not aware of the controls it will be associated with.
Basically RoutedCommands works great in certain scenarios, and are prevalent in WPF. The thing is, routed commands are not always great fit for MVVM development. Because if we used the RoutedCommand, we need to use a CommandBinding somewhere in the UI in order to connect a VisualElement to the respective command. So we would likely stick the usage the RoutedCommands in MVVM.
But with the help of DelegateCommand everything is simple. It will have CanExecute and Execute callbacks to achieve this. It executes the different method in the ViewModel.

public class DelegateCommand : ICommand
    {

        Predicate<object> canExecute;
        Action<object> execute;

        public DelegateCommand(Predicate<object> _canexecute,Action<object> _execute)
            :this()
        {
            canExecute = _canexecute;
            execute = _execute;
        }

        public DelegateCommand()
        {

        }

        public bool CanExecute(object parameter)
        {
            return canExecute == null ? true : canExecute(parameter);
        }

        public event EventHandler CanExecuteChanged;

        public void Execute(object parameter)
        {
            execute(parameter);
        }
    }

In this sample, DataGrid will updates the Rows based on the ItemsSource updates from the ViewModel.
Each and every Row will be having the Delete button which invokes the DelegateCommand to delete the SelectedRow from the DataGrid.

<DataGridTemplateColumn>
      <DataGridTemplateColumn.CellTemplate>
          <DataTemplate>
               <Grid>
                   <Button Content="Remove..." Margin="3" Command="{Binding Path=DataContext.RemoveCommand,RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" 
                                        CommandParameter="{Binding}"/>
               </Grid>
          </DataTemplate>
      </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

It will execute the Remove action from the connected observable collection. That means , it just Remove the selected item from the collection. As ObservableCollection is ICollectionChanged interface, it updates the View at the time when collection modified in the ViewModel.