Pages

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.



Saturday, May 12, 2012

3D image animation in WPF using Blend 4

Welcome to my blog... Here i am gonna to show my first experiment in 3D animation using Blend. It is pretty to easy to play the 3D using Blend 4. 

1 . Open the Blend 4 and create the new WPF application.


2. Add an image to the project through Add Existing item then drag and drop to the designer space.




3. After the image has been inserted to the designer space adjust the image using the selection tool to fit to the designer space. Now we are going to make this image to 3D using the following steps.
Go to the option Tools -> Make 3D image in the Blend.
4. In this step we are going to rotate this image in the 3D workspace. We have special tool in the tool box Camera Orbit to achieve this in Blend. Select the Camera Orbit.
5. Now click on the selected image and rotate it as per your wish.. Wow... its awesome.. It is really interesting to do the 3D animation with this option.
6. Once we have done this rotation with the image go to the Direction selection tool in the Toolbox and select the image. It will show the rotating tag with the image with green and red color. It will helpful to rotate the image as per your wish.


It is really interesting to me to play these kind of animations in WPF.. I will post a rotating cube animations in my upcoming updates.

Generated XAML

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
        mc:Ignorable="d"
        x:Class="WpfApplication1.MainWindow"
        x:Name="Window"
        Title="MainWindow"
        Width="640" Height="480">
 
 <Grid x:Name="LayoutRoot">
  <Viewport3D Margin="130,25,205,36">
   <Viewport3D.Camera>
    <PerspectiveCamera FieldOfView="45" FarPlaneDistance="100" 
                       LookDirection="7.434,-1.118,-16.698" 
                       NearPlaneDistance="0.1" Position="-7.434,1.118,16.698" 
                       UpDirection="0.025,0.998,-0.056"/>
   </Viewport3D.Camera>
   <ModelVisual3D x:Name="ModelContainer">
    <ModelVisual3D.Content>
     <GeometryModel3D x:Name="Model" d:Bounds="-7.58530183727034,-10,0,15.1706036745407,20,0">
      <GeometryModel3D.Geometry>
       <MeshGeometry3D Normals="0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,
0,1 0,0,1 0,0,1 0,0,1 0,0,10,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,
0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,
0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,
0,1 0,0,10,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1
0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1
0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1
0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1" 
Positions="-7.5853018,-10,0 -5.8996792,
-10,0 -4.2140566,-10,0 -2.5284339,-10,0 -0.84281132,-10,0 0.84281132,-10,0 2.5284339,
-10,0 4.2140566,-10,0 5.8996792,-10,0 7.5853018,-10,0 -7.5853018,-7.7777778,0 -5.8996792,
-7.7777778,0 -4.2140566,-7.7777778,0
-2.5284339,-7.7777778,0 -0.84281132,-7.7777778,0 0.84281132,-7.7777778,0 2.5284339,
-7.7777778,0 4.2140566,-7.7777778,0 5.8996792,-7.7777778,0 7.5853018,-7.7777778,0 -7.5853018,
-5.5555556,0 -5.8996792,-5.5555556,0 -4.2140566,-5.5555556,0 -2.5284339,-5.5555556,
0 -0.84281132,-5.5555556,0 0.84281132,-5.5555556,0
2.5284339,-5.5555556,0 4.2140566,-5.5555556,0 5.8996792,-5.5555556,0 7.5853018,-5.5555556,
0 -7.5853018,-3.3333333,0 -5.8996792,-3.3333333,0 -4.2140566,-3.3333333,0 -2.5284339,
-3.3333333,0 -0.84281132,-3.3333333,0 0.84281132,-3.3333333,0 2.5284339,-3.3333333,
0 4.2140566,-3.3333333,0 5.8996792,-3.3333333,0
7.5853018,-3.3333333,0 -7.5853018,-1.1111111,0 -5.8996792,-1.1111111,0 -4.2140566,
-1.1111111,0 -2.5284339,-1.1111111,0 -0.84281132,-1.1111111,0 0.84281132,-1.1111111,
0 2.5284339,-1.1111111,0 4.2140566,-1.1111111,0 5.8996792,-1.1111111,0 7.5853018,
-1.1111111,0 -7.5853018,1.1111111,0 -5.8996792,1.1111111,0
-4.2140566,1.1111111,0 -2.5284339,1.1111111,0 -0.84281132,1.1111111,0 0.84281132,
1.1111111,0 2.5284339,1.1111111,0 4.2140566,1.1111111,0 5.8996792,1.1111111,
0 7.5853018,1.1111111,0 -7.5853018,3.3333333,0 -5.8996792,3.3333333,0 -4.2140566,3.3333333,
0 -2.5284339,3.3333333,0 -0.84281132,3.3333333,0
0.84281132,3.3333333,0 2.5284339,3.3333333,0 4.2140566,3.3333333,0 5.8996792,3.3333333,
0 7.5853018,3.3333333,0 -7.5853018,5.5555556,0 -5.8996792,5.5555556,0 -4.2140566,5.5555556,
0 -2.5284339,5.5555556,0 -0.84281132,5.5555556,0 0.84281132,5.5555556,0 2.5284339,5.5555556,
0 4.2140566,5.5555556,0
5.8996792,5.5555556,0 7.5853018,5.5555556,0 -7.5853018,7.7777778,0 -5.8996792,7.7777778,0 
-4.2140566,7.7777778,0 -2.5284339,7.7777778,0 -0.84281132,7.7777778,0 0.84281132,7.7777778,
0 2.5284339,7.7777778,0 4.2140566,7.7777778,0 5.8996792,7.7777778,0 7.5853018,7.7777778,
0 -7.5853018,10,0
-5.8996792,10,0 -4.2140566,10,0 -2.5284339,10,0 -0.84281132,10,0 0.84281132,10,0 2.5284339,
10,0 4.2140566,10,0 5.8996792,10,0 7.5853018,10,0" 
TextureCoordinates="0,381 32.111111,381 64.222222,381 96.333333,381 128.44444,381 160.55556,
381 192.66667,381 224.77778,381 256.88889,381 289,381 0,338.66667 32.111111,
338.66667 64.222222,338.66667 96.333333,338.66667 128.44444,338.66667 160.55556,
338.66667 192.66667,338.66667 224.77778,338.66667 256.88889,338.66667 289,338.66667 0,
296.33333 32.111111,296.33333 64.222222,296.33333
96.333333,296.33333 128.44444,296.33333 160.55556,296.33333 192.66667,
296.33333 224.77778,296.33333 256.88889,296.33333 289,296.33333 0,254 32.111111,
254 64.222222,254 96.333333,254 128.44444,254 160.55556,254 192.66667,254 224.77778,
254 256.88889,254 289,254 0,211.66667 32.111111,211.66667 64.222222,211.66667 96.333333,
211.66667 128.44444,211.66667 160.55556,211.66667
192.66667,211.66667 224.77778,211.66667 256.88889,211.66667 289,211.66667 0,
169.33333 32.111111,169.33333 64.222222,169.33333 96.333333,169.33333 128.44444,
169.33333 160.55556,169.33333 192.66667,169.33333 224.77778,169.33333 256.88889,
169.33333 289,169.33333 0,127 32.111111,127 64.222222,127 96.333333,127 128.44444,
127 160.55556,127 192.66667,127 224.77778,127 256.88889,127
289,127 0,84.666667 32.111111,84.666667 64.222222,84.666667 96.333333,84.666667 128.44444,
84.666667 160.55556,84.666667 192.66667,84.666667 224.77778,84.666667 256.88889,
84.666667 289,84.666667 0,42.333333 32.111111,42.333333 64.222222,42.333333 96.333333,
42.333333 128.44444,42.333333 160.55556,42.333333 192.66667,42.333333 224.77778,
42.333333 256.88889,42.333333 289,42.333333 0,0 32.111111,0
64.222222,0 96.333333,0 128.44444,0 160.55556,0 192.66667,0 224.77778,0 256.88889,0 289,0" 
TriangleIndices="0 1 10 1 11 10 1 2 11 2 12 11 2 3 12 3 13 12 3 4 13 4 14 13 4 5 14 5 15 14 
5 6 15 6 16 15 6 7 16 7 17 16 7 8 17 8 18 17 8 9 18 9 19 18 10 11 20 11 21 20 11 12 21 12 22
 21 12 13 22 13 23 22 13 14 23 14 24 23 14 15 24 15 25 24 15 16 25 16 26 25 16 17 26 17 27 26
 17 18 27 18 28 27 18 19 28 19 29 28 20 21 30 21 31 30 21 22 31 22 32 31 22 23 32 23 33 32 23
 24 33 24 34 33 24 25 34 25 35 34 25 26 35 26 36 35 26 27 36 27 37 36 27 28 37 28 38 37 28 29 
38 29 39 38 30 31 40 31 41 40 31 32 41 32 42 41 32 33 42 33 43 42 33 34 43 34 44 43 34 35 44 
35 45 44 35 36 45 36 46 45 36 37 46 37 47 46 37 38 47 38 48 47 38 39 48 39 49 48 40 41 50 41
 51 50 41 42 51 42 52 51 42 43 52 43 53 52 43 44 53 44 54 53 44 45 54 45 55 54 45 46 55 46 56
 55 46 47 56 47 57 56 47 48 57 48 58 57 48 49 58 49 59 58 50 51 60 51 61 60 51 52 61 52 62 61 
52 53 62 53 63 62 53 54 63 54 64 63 54 55 64 55 65 64 55 56 65 56 66 65 56 57 66 57 67 66 57 
58 67 58 68 67 58 59 68 59 69 68 60 61 70 61 71 70 61 62 71 62 72 71 62 63 72 63 73 72 63 64 
73 64 74 73 64 65 74 65 75 74 65 66 75 66 76 75 66 67 76 67 77 76 67 68 77 68 78 77 68 69 78
 69 79 78 70 71 80 71 81 80 71 72 81 72 82 81 72 73 82 73 83 82 73 74 83 74 84 83 74 75 84 75 
85 84 75 76 85 76 86 85 76 77 86 77 87 86 77 78 87 78 88 87 78 79 88 79 89 88 80 81 90 81 91 
90 81 82 91 82 92 91 82 83 92 83 93 92 83 84 93 84 94 93 84 85 94 85 95 94 85 86 95 86 96 95 
86 87 96 87 97 96 87 88 97 88 98 97 88 89 98 89 99 98"/>
      </GeometryModel3D.Geometry>
      <GeometryModel3D.Material>
       <DiffuseMaterial>
        <DiffuseMaterial.Brush>
         <ImageBrush ImageSource="pack://siteoforigin:,,,/Photo0089.jpg" Stretch="Fill"/>
        </DiffuseMaterial.Brush>
       </DiffuseMaterial>
      </GeometryModel3D.Material>
     </GeometryModel3D>
    </ModelVisual3D.Content>
   </ModelVisual3D>
   <ModelVisual3D x:Name="AmbientContainer">
    <ModelVisual3D.Content>
     <AmbientLight x:Name="Ambient" Color="Gray"/>
    </ModelVisual3D.Content>
   </ModelVisual3D>
   <ModelVisual3D x:Name="DirectionalContainer">
    <ModelVisual3D.Content>
     <DirectionalLight x:Name="Directional" Color="#FF7F7F7F" Direction="0,0,-1">
      <DirectionalLight.Transform>
       <TranslateTransform3D OffsetZ="3" OffsetX="0" OffsetY="0"/>
      </DirectionalLight.Transform>
     </DirectionalLight>
    </ModelVisual3D.Content>
   </ModelVisual3D>
  </Viewport3D>
 </Grid>
</Window>

I hope after this .. You will be interested to work with 3D animation .. :)