Now that the ContactCollectionViewModel class has been created, you can go ahead and create the first View, which displays a data table.
Right-click the project in the Solution Explorer and select Add DevExpress Item | New Item… to invoke the DevExpress Template Gallery. Select the View (Blank User Control) template and specify the name as ContactCollectionTableView.
Open the designer and place the ContactCollectionViewModel in the DataContext of the created View.
Since ContactCollectionViewModel is a POCO class, it is necessary to create its instance with ViewModelSource.
Step 2 - Adding a RibbonControl
The View will contain a GridControl that shows table data and several commands for working with this data. The commands will be displayed in the Ribbon.
Add a Ribbon Control with the DevExpress Instant Layout Assistant, which appears in the center of the white space on the design surface. Select Ribbon Control | Empty Ribbon.
Using the smart tag menu, you can customize the RibbonControl - modify properties, add bar items, etc. BarItem Glyphs can be set from the DevExpress.Images library.
Continue customizing the RibbonControl to get the following layout.
Next, add a GridControl with a detail form. To arrange the GridControl and detail form, select LayoutControl | Grid Details Layout in the Instant Layout Assistant. The Instant Layout Assistant provides a predefined template with the required layout.
The DataContext property of our View contains a ContactCollectionViewModel object. This ViewModel provides two properties: Entities and SelectedEntity. The first property provides database records and the second one provides the current record. Bind GridControl.ItemsSource and GridControl.SelectedItem to these ViewModel properties.
Currently, the GridControl shows all columns. These columns are not defined in XAML; they are generated by the GridControl based on the data source type. To hide unnecessary columns, it is necessary to strongly define the columns in XAML.
Click the Generate Columns action in the GridControl's smart tag menu. Then, disable runtime column generation by setting the AutoGenerateColumns property to None, and disable horizontal scrolling by setting the AutoWidth property to True.
Next, bind the Find BarButtonItem. When an end-user clicks it, GridControl shows a Search Panel. The TableView.TableViewCommands provides a command for this purpose – ShowSearchPanel. This command takes a Boolean parameter that controls whether the Search Panel should be focused on showing. Always pass the True value to the command.
Bind the Find BarButtonItem to get the following code.
The Delete BarButtonItem, which provides the DeleteCommand, should be bound to the ViewModel. This command requires a parameter – the row to be deleted. Thus, CommandParameter should be bound to the SelectedEntity property of the ViewModel. (This property is bound to GridControl.SelectedItem.)
Run the application and check the results. Notice that the New and Find commands work properly, but if you click the Delete button, there is an error in ContactCollectionViewModel because its MessageBoxService property is Null. To fix this issue, add DXMessageBoxService.
Only two issues are left unresolved. The first is that the Model (the Contact class) does not support the INotifyPropertyChanged interface. As a result, when a user changes a cell value in the GridControl, the detail form is not updated.
ContactCollectionViewModel provides the UpdateSelectedEntityCommand, which raises the PropertyChanged event for the SelectedEntity property. Since the detail form is bound via the SelectedEntity property, we can call UpdateSelectedEntityCommand when a cell value is changed (i.e., in the TableView.CellValueChanged event handler). To accomplish this task using the MVVM pattern, use the EventToCommand. Open the designer and invoke the GridControl's smart tag menu, switch to the Services tab and add an EventToCommand.
First, you will need to set the source element – the element that provides the event you wish to handle. In this example it is the TableView. Enter the name of the TableView in the SourceName box (if the TableView does not yet have a name, set it first), select the CellValueChanged event in the EventName box, and bind the EventToCommand.Command property.
The last issue that needs to be resolved is saving changes to the database. When an end-user modifies a row, the modifications should be saved. To fix this issue, call ContactCollectionViewModel.SaveCommand when the TableView.RowUpdated event is raised.
Note that the SaveCommand requires a row as a parameter. For this purpose, bind CommandParameter to SelectedEntity.