Implementing the RowViewModel – Part 2

Part 2 – Getting Data into the Grid

In Part 1, we setup the projects necessary for a standard business application using IdeaBlade DevForce for the Model, MVVM Light for the ModelView and a Telerik RadGridView in the View.

In Part 3, we will follow through the binding process to see some of the challenges posed when making the grid editable.

In Part 2, we will make the changes necessary to make the grid editable.

Requirements

For this part of the sample, the requirements are as follows:

  1. Show Orders in the Rows of the Grid.
  2. Make the Grid Editable.
  3. Save changes to the Orders with a Save Changes button.

Showing the Orders in the Grid

This will require adding an Orders property to the MainViewModel; populating that property and then binding the Orders property to the grid.

  1. Make sure there is a reference in the Web project to the server-side Model project.
  2. Open the MainViewModel.cs file.
  3. Remove the Welcome property.
  4. Open the ViewModel\MainViewModel.cs file.
  5. Use the mvvminpc Snippet to add an Orders property.
    /// <summary>
    /// The <see cref="Orders" /> property's name.
    /// </summary>
    public const string OrdersPropertyName = "Orders";
    
    private ObservableCollection<order> _orders;
    
    /// <summary>
    /// Gets the Orders property.
    /// TODO Update documentation:
    /// Changes to that property's value raise the PropertyChanged event. 
    /// This property's value is broadcasted by the Messenger's default instance when it changes.
    /// </summary>
    public ObservableCollection<order> Orders
    {
        get
        {
            return _orders;
        }
    
        set
        {
            if (_orders == value)
            {
                return;
            }
    
            //var oldValue = _orders;
            _orders = value;
    
            // Remove one of the two calls below
            //throw new NotImplementedException();
    
            // Update bindings, no broadcast
            RaisePropertyChanged(OrdersPropertyName);
    
            // Update bindings and broadcast change using GalaSoft.MvvmLight.Messenging
            //RaisePropertyChanged(OrdersPropertyName, oldValue, value, true);
        }
    }
  6. Next, add a method to fill the collection.
    private void GetOrdersAsync()
    {
        var em = new NorthwindIBEntities();
        var qry = em.Orders;
        em.ExecuteQueryAsync(qry, args =>
             this.Orders = new ObservableCollection<order>(args.Results));
    }
  7. Next, add a call to the new method in MainViewModel constructor:
    public MainViewModel() 
    { 
        GetOrdersAsync();
  8. Finally, add a binding to the XAML to show the Orders in the Grid.  (Set the ItemsSource of the RadGridView to Orders.)
    <telerik:RadGridView Name="radGridView1" ItemsSource="{Binding Path=Orders}" Height="775" Width="1000" />
  9. Build and Run.  After a moment or two, you should see the grid, fully populated with Orders.
    image

Making the Grid Editable

For once, the default behavior is desirable.  We get this for free because the RadGridView is editable by default.  Due to the magic of Binding, the Order objects are getting updated whenever a cell in the grid is edited.

Saving the Changes

Saving those changes will require us to have a button bound to an ICommand that will tell the EntityManager to save all the changes.

  1. In MainPage.xaml, add a button to the StackPanel above (or below) the RadGridView.
    <Button Content="Save" Height="23" Name="SaveAllButton" Width="75" HorizontalAlignment="Left" />
  2. In MainViewModel.cs, add a new RelayCommand named SaveAllCommand.
    public RelayCommand SaveAllCommand
    {
        get;
    	private set;
    }
  3. In the MainViewModel constructor, add a line to instantiate the command:
    SaveAllCommand = new RelayCommand(this.SaveAllOrders);
  4. Now add the SaveAllOrders method and the SaveAllButtonEnabled property:
    private void SaveAllOrders()
    {
        this.SaveAllButtonEnabled = false;
        _entityManager.SaveChangesAsync(args => 
            this.SaveAllButtonEnabled = true);
    }
    
    public bool SaveAllButtonEnabled
    {
        get
        {
            return _saveAllButtonEnabled;
        }
        set
        {
            _saveAllButtonEnabled = value;
            RaisePropertyChanged("SaveAllButtonEnabled");
        }
    }
  5. Now you can go back to the button to set the bindings:
    <Button Content="Save" Height="23" Name="SaveAllButton" Width="75" HorizontalAlignment="Left" IsEnabled="{Binding Path=SaveAllButtonEnabled}" Command="{Binding Path=SaveAllCommand}" />
  6. Build and Run. After a moment or two, you should see the grid, fully populated with Orders. Try editing some of the orders and hit Save All. Refresh the page to see that the changes were saved.

What’s next?

So now you have an editable grid. So far, we have not needed the RowViewModel. If you only want SaveAll functionality, the default behavior of the grid will suffice. The grid lets you edit any cell all the time and the bindings keep the model up to date. A simple call to entity manager to save the changes and all is well.
However, if you want some entity specific functionality, you will find it quite cumbersome to try to deal with this within the context of the grid’s ViewModel as it is really only concerned with the grid and entire grid related actions (such as Save All).

In Part 3, we will add some entity specific requirements so we can see how to use the RowViewModel to make working with the entities in the grid much simpler.

Implementing the RowViewModel – Part 1

 

Part 1 – Setting up the Projects

In my earlier post here, I introduced the concept of a RowViewModel to make editable grids using the MVVM pattern.  In this post, I will demonstrate how to implement the RowViewModel using a combination of IdeaBlade DevForce for the Model, MVVMLite for ViewModel support and Telerik’s Silverlight RadGridView for the View.

Prerequisites:

  1. IdeaBlade DevForce 6.0.7 or later.
  2. Telerik Silverlight Controls 2010.3 or later.
  3. MVVM Light Toolkit
  4. VisualStudio 2010 and Silverlight 4
  5. Silverlight 4 Toolkit

Assumptions:

  1. We’ll use IdeaBlade’s sample database:  NorthwindIB.  This can be found in the \Program Files\DevForce 2010\ folder.
  2. I have way too many VS add-ins installed so my screen shots may not appear as your screen does.
  3. I do use JetBrains Resharper and Telerik’s JustCode, so some of the refactorings and shortcuts may not be available if you do not have these tools.

Creating the Beginning State

  1. Per the article and sample shown at MVVM Light with DevForce, we will create a sample app using the MVVM Light SL4 template.  (I.e. Set up their MvvmLite1 example.)
    image
  2. Then add the DevForce Silverlight Application project.
    image
  3. Delete the README_FIRST files.
  4. In the Model project:
    1. Delete App.xaml and MainPage.xaml.
    2. Rename the project with SL suffix.  Do not rename the Assembly with the SL suffix and do not change the namespace.
  5. In the Application project:
    1. Add a reference to the Model project.
    2. Add references to the DevForce assemblies referenced in the Model project.
      image
    3. In the properties for the DevForce assemblies, change the Copy Local to True and the Specific Version to False.
      image
    4. Add a reference to System.Runtime.Serialization.
  6. In the Web project:
    1. Rename the web project to remove the word Model.
    2. In the project properties:
      1. Rename the Assembly and the namespace.
      2. On the Silverlight Applications tab, remove the dead DevForce Silverlight app project (if present).
        Add the Silverlight Application (e.g. RVMSample). 
    3. Delete the test HTML page and the Default.aspx page.
    4. Set the Web project as the Startup Project. 
    5. Set the new test ASPX page as the Start Page.
    6. Delete the XAP file from the ClientBin folder.
  7. Save and Close the solution.
  8. Rename the project folders to match the project names.
  9. Edit the .SLN file in a text editor to correct the folder names there too. 
    image
  10. Open the solution in VS.
  11. Build and Run.  Nothing so far has changed the functionality so it should work fine:   
    image    

Creating the Server-Side Model Project

So far so good.  We have setup the three-project solution.  Unfortunately, this means we’re going to load the EDMX into the Web project, which hardly seems fitting.  Let’s create a server-side project to house the server side Model.

  1. Add a regular Class Library project as the server side Model.  This should be named application.Model.
  2. Delete Class1.
  3. In the Web project, add a reference to the application.Model project.
  4. Add an ADO.Net Entity Data Model name it NorthwindIBModel.
  5. Select to Generate from database.
  6. Connect to the NorthwindIB database.
  7. Select the following tables:
    Customer
    Employee
    Order
    OrderDetail
    Product
  8. Change the namespace to application.Model.
  9. Wait while the Entity Manager and IdeaBlade do their code generation.  IdeaBlade will also make a link from the Model.SL project to the Model project so they share code.
  10. Copy the new connectionString settings from app.config in this project to web.config in the web project.
  11. Build the solution to make sure all the references are configured properly.  Run the app.  See nothing has changed yet. :)

Adding the Grid to the View

Great, now we have client-side (Model.SL) and server-side (Model) model projects, a Silverlight application project and a Web project to host it all in.  Let’s go ahead and add the Telerik Grid to the project, then we can finally start looking at the Row-View-Model pattern.

  1. In the application project, open the MainPage.xaml.
  2. Change the Width and Height of the page to 1000 x 800.
  3. Remove the TextBlock that is there.
  4. Change the <Grid> to a <StackPanel>.
  5. In the <StackPanel>, drag and drop a Telerik RadGridView from the Toolbox.
  6. Change the Width and Height of the RadGridView to 1000 x 800.
  7. Build the solution to make sure all the references are configured properly.
  8. Run the application.  You should see the empty Telerik grid in your browser:
    image

Ta da!  All that work to set up the beginning state for exploring RVM.  In my next posting, you will get the requirements for the grid and see how we can use the RowViewModel to make in-line grid editing much simpler.

IdeaBlade DevForce – Model Setup Walk-through – Sample Code

Attached here is the finished sample project, created by following the steps outlined in the IdeaBlade DevForce – Model Setup Walk-through:
Background
Step 1: The Entity Framework Project
Step 2: The DevForce Projects

Attached Code: Sample Code

Notes:
Of course I had to adjust the connection string in the ModelEF’s app.config file.
The SQL to create the tables is in the Step 1 instructions linked above.
I have not included the DLL’s and Installs in the dependencies and installations folders. These can be readily downloaded from the various vendors’ sites.

IdeaBlade DevForce – Model Setup Walk-through – Step 2: The DevForce Projects

Our Problem:


We need to create an Enterprise application that is web-based, has an Excel-ish interface and pulls data from an Oracle database.

Technologies Chosen*:

  • Silverlight for the UI
  • Prism 2 for the modular framework
  • Unity for DI
  • IdeaBlade DevForce for the Business Object Layer and Async functionality
  • MS Entity Framework for the ORM
  • DevArt dotConnect for Oracle (EF Drivers)
  • Oracle 11 Database

* See here for our reasoning.

Prerequisites:

  1. Complete the procedures documented in Step 1
  2. Install IdeaBlade’s DevForce for Silverlight tool.
  3. Install the Silverlight development environment. This comprises:
    1. The Silverlight 3 Developer Runtime
    2. The Silverlight 3 Tools for VS 2008
    3. The Silverlight 3 SDK

Creating the DevForce model projects:


There will be two DevForce model projects, one will be a C# library project that runs on the server, the other will be a Silverlight library that runs in the Silverlight client. The DevForce framework takes care of wiring these two together with a couple of WCF services that are hosted in the Web application that hosts the DevForce components and the Silverlight app.

To create the projects:

  1. Open the Entity Framework model solution created in Step 1 of this walkthrough.
  2. Select Tools | DevForce Object Mapper
  3. DevForce naturally works with EDMX files (Model | Add Entity Model), but we have an EDML file from the devArt Entity Developer, so we have to use File | Open to get to it.

    Select File | Open, change the Files of type to All Files. Select the Model_Widget.edml file and click Open.
    At this point, DevForce has opened the EF model. Now, we have to tell it how we want the projects to be configured.

  4. First, click the New Project button for the Domain Model project.
    The Project Name needs to follow our assembly naming convention, so for this walkthrough, I am using Acme.BirdTrap.Model.Widget (with no suffix).
    I will leave the Project Type and Location at their defaults.
  5. Second, click the New Project button for the Silverlight project.
    The Project Name needs to follow our assembly naming convention, so for this walkthrough, I am using Acme.BirdTrap.Model.WidgetSL (with the SL = Silverlight suffix).
    I will leave the Project Type and Location at their defaults.
  6. Back on the new model tab:
    1. Set the Namespace to: Acme.BirdTrap.Model.Widget
    2. Set the EntityManager name to something more model specific, we use a standard of ModuleEntityManager as the application may need to work with multiple modules’ EntityManagers at the same time.
      I have selected to name the Entity Manager: WidgetEntityManager.

    New Devforce Project Settings

    [Note: See Ward Bell's essay on the topic of Large Models for more about splitting your model and using multiple Entity Managers.]

  7. Select the Model_WidgetEF.edml branch of the Model tree on the left. You will see the settings available for this EF Model.
    1. Change the DataSourceKeyName to something more model specific, we use a standard of ModuleDataSource as each module/model needs a different DataSource definition.
      I have selected to name the Data Source Key: WidgetDataSource
    2. This is also the place where you inject your own base Entity class implementations into the DevForce model. At the very least, you should create a BaseEntity class where you can put common Entity functionality. Click the Injected Base Types button and add Acme.BirdTrap.Utility.Persistence.BaseEntity to the list, setting it as the default. (In a future posting, I will be examining the Injected Base Types in greater depth.)
    3. The name pluralizer is a great feature of DevForce but it is completely irrelevant to us as devArt’s Entity Developer tool has taken care of pluralization for us.

  8. Click the Save button on the toolbar. DevForce will now create and initialize the two projects we have defined. When it has finished, close the DevForce Object Mapper.
  9. Next, we need to create the BaseEntity class we added to the Injected Base Types earlier.
    1. In the new C# project, Acme.birdTrap.Model.Widget, add a new class named Acme.BirdTrap.Utility.Persistence.BaseEntity that inherits from IdeaBlade.EntityModel.Entity
      using IdeaBlade.EntityModel;
      
      namespace Acme.BirdTrap.Utility.Persistence
      {
          public class BaseEntity : Entity
          {   
          }
      }
    2. In the new Silverlight project, Acme.birdTrap.Model.WidgetSL, add an Existing Item, then navigate to the BaseEntity class you just created in the C# project, drop down the Add button and choose Add as Link.
  10. I bet you wish we were done at this point. We are not. DevForce made some assumptions in generating the projects that we need to fix.

    First, and really only a cosmetic issue, DevForce created a Solution Folder for the DomainModel. You can choose to keep this or not. This whole solution is for my DomainModel, so I do not need this new folder. If I incorporate the Model projects into a larger Module level Solution, then I will use a Solution Folder for the Model projects in that solution, but I do not need one here. To remove the folder, I drag the two new projects up out of the folder into the Solution level and then Remove the folder.

  11. Second, and by far more serious, DevForce pulled in a bunch of referenced components, some of theirs, some of the .Net Framework’s and some from the Silverlight SDK.
    There are three places where referenced assemblies can safely live:

    1. \WINDOWS\Microsoft.NET\Framework\**.*
    2. \Program Files\Reference Assemblies\**.*
    3. Your solution’s dependencies\**.*

    1. Examining the C# project (Acme.BirdTrap.Model.Widget), we find the IdeaBlade assemblies are referenced from Program Files. We can change that by: first, removing the Ideablade.Core, Ideablade.EntityModel, Ideablade.Validation,assemblies; then adding them back from the dependencies\IdeaBlade DevForce\ folder.
    2. Examining the Silverlight project (Acme.BirdTrap.Model.WidgetSL), we find the IdeaBlade Silverlight assemblies are referenced wrong, which can be corrected as above, only adding back from the dependencies\IdeaBlade DevForce\SilverlightAssemblies folder this time.
      However, we also find that the System.ComponentModel.DataAnnotations assembly is being pulled from \Program Files\Microsoft SDKs\ folder. Remove it and add it back from dependencies\Silverlight\Libraries\Client\.
  12. That’s it, right? We’ve created the files and all is well. If you try to Build your solution right now, you will get errors originating from the EF project. But it was fine before we started, and we didn’t change it — or did we?
    In fact, we did. When you point the DevForce Object Mapper at the EF project’s EDML file, DevForce adds a bunch of attributes to some of the elements in that file. In doing so, the DevArt Entity Developer notices the EDML has changed and wipes the generated *.designer.cs file. To restore this, you need to re-open the EDML file and regenerate the generated code. But here’s the rub, if you open the EDML file from within Visual Studio, the devArt Entity Developer will only regenerate the code if you make changes to the model. But we don’t want to make changes to the model.
    Instead, open the EDML file from Windows Explorer. This will open the Entity Developer and reveal a Generate Code button on the toolbar:
    Generate Code button
    Clicking this button, will regenerate the missing generated code without requiring a model change. You can then exit the Entity Developer.
  13. DONE.

Conclusion


In this part of the walk through, we have created the pair of DevForce C# and Silverlight projects that contain our Domain Model.
The solution successfully Builds and the EF unit test we created in Step 1 still passes. Now we need to create a pair of Unit Test projects to ensure that the DevForce framework is configured properly and can successfully CRUD the database through the EF layer. But that will have to wait until the next part of the walk through.

Until then: I’m off to take the dog for a walk! Woof!

IdeaBlade DevForce – Model Setup Walk-through – Background

I know the world is about to change in April when VS2010 goes live, however, we are still using VS2008 and will be for at least a few more weeks.  In the hopes that this walk-through provides some insight to someone, even if it is just me, here goes.

Background

We are  creating a Silverlight application for several reasons:

  1. Web development is not nearly complex enough, so we sought out a unique challenge involving the newest, least documented, voted most-likely-to-be-completely-re-done-in-the-next-version technology (excepting WWF, I mean, WF, which will probably hold that distinction for years to come).
  2. Our users do everything in Excel, meaning that much of the data entry UI for this app needs to be as Excel-ish as possible, including the dreaded Multi-Add (adding multiple rows between saves) and Multi-Edit (editing multiple rows between saves).  [FYI: It turns out that none(?) of the OTC Grids are actually designed for this.  You can make it work with Telerik if you want to try hard.  See postings like this one in Telerik's forums for more info.  They have come a long way since that posting.]
  3. Management is opposed to fat client or virtualization, so the app has to be web-based.
  4. After much trial-and-error, and trial-and-failure, and trial-and-compromise, we deployed an ASP/Ajax solution that was less than satisfactory and not-at-all Excel-ish, so we had to find a “better way”.
  5. We have a code base that comprises 8 years of work in VB 6, classic ASP, ASP.Net 1, ASP.Net 2, ASP.Net 3.5, VB.Net (all sorts), Infragistics (an old version), Telerik (several versions), copious quantities of javascript, several generations of CSS and DHTML, including many of the really exotic first generation tricks, Ajaxified ASP pages, ASP/Ajax pages and an Oracle back-end, so we knew that ASP was not going to give us what we needed.
  6. None of us had ANY desire to explore Flex.
  7. We are a Microsoft shop, so building a Java app was not really an option.
  8. Silverlight 3 was coming and promised enough features for us to begin writing an Enterprise app.  (It turns out that we jumped the gun on this, but we were not alone and SL4 promises to remedy many of the “it’s-not-ready-for-the-enterprise” issues.)

We are using DevForce and the Entity Framework because:

  1. Having worked with Hibernate, NHibernate, and SubSonic (which I preferred over NHibernate), I was convinced that a Data Layer / ORM would make our application specific code much easier to write and would provide more and better infrastructure/plumbing than we ever could.
  2. Having been told:  “No Open Source”  and given 3 weeks to pull SubSonic out of a working project and replace it with a roll-my-own ORM, I knew that many features we needed (Concurrency and caching, to name just two) were going to be a HUGE effort to write myself, and that if this was a Make or Buy decision, that Buy was clearly the better choice.  (Check out Davy Brion’s Build Your Own Data Access Layer Series for a deeper examination of the Make option.)
  3. Having been exposed to DevForce Classic a few years ago, I knew their product provided much of what we needed, and they were on the cusp of releasing a Silverlight version of their WPF framework.  As an added bonus, their documentation, and Ward Bell’s blog, are highly readable and provide excellent project guidance and design philosophy.
  4. DevForce sits on top of Entity Framework, which does not support Oracle, but as this was about to kill the deal, we found that DevArt’s Oracle drivers were finally supporting EF properly.

We are using Prism and Unity because:

  1. If you’re gonna do this thing, you might as well go all in.
  2. Having worked with CAB for a Windows App, I understood the potential of a component based application framework — or at least imagined I understood it, can anyone really understand anything PnP publishes?
  3. After dabbling in the Java world for a few months, I had developed an appreciation for Spring, Dependency Injection, configuration over coding and convention over configuration.
  4. I am unrepentant about preferring Agile development practices, and many of the “best practices” prescribed by PnP and implemented in Prism, represent many Agile coding principles in action.  Both VersionOne and RallyDev have Agile 101 documentation on-line.   Mike Cohn has written several excellent books introducing teams to Agile practices.

So we ended up with the following technology stack:

  1. Prism 2 for its Modular framework
  2. Unity for Dependency Injection
  3. Microsoft Silverlight 3 for the UI
  4. Telerik for Silverlight for several of its UI components (alas, we still have to do far too much ourselves in this area though)
  5. IdeaBlade DevForce for Silverlight for its Silverlight friendly Business Entity model and asynchronous client-server communication layer
  6. DevArt dotConnect for Oracle drivers for its support of the MS Entity Framework and it’s excellent Entity Developer tool
  7. Microsoft Entity Framework for the server-side Entity Model and database connectivity
Follow

Get every new post delivered to your Inbox.