ComponentOne Data Source for Entity Framework
Design-Time Features / Live Views
In This Topic
    Live Views
    In This Topic

    Live views is a powerful feature, so let’s take a little more time to see what live views can do. Live views are designed to make data binding more powerful, so powerful, in fact, that you can develop virtually entire applications with just LINQ (in its LiveLinq form) and data binding.

    Live views, called LiveLinq, a part of DataSource for Entity Framework, is a client-side, in-memory feature applicable not only to Entity Framework and RIA Services data, but to any observable collections in memory, including XML (LINQ to XML object model) and ADO.NET DataSets.

    So, for example, you can use live views over Entity Framework data and some other data (for example, XML retrieved from some web service) to integrate that data and to provide easy full-featured data binding to the integrated data. This is a powerful tool for building applications that get data from various sources. For now we’re going to concentrate on how we can use it with the Entity Framework, but if you’d like to explore LiveLinq in greater depth, see the ComponentOne LiveLinq documentation.

    In fact, we already saw an example of such customization in Customizing View. But there we only changed the properties (fields) of the view and only applied one LINQ operator, Select. Let’s apply some more LINQ operators to transform the view. What we do here will be similar to what we did in Customizing View, but instead of using C1DataSource, we’ll be doing everything in code.

    To use live views, follow these steps:

    1. Add a new form using the project created to demonstrate Working with DataSources in Code, and add a data grid, dataGridView1, to the form.
    2. Add the following code to the form class. Here we are following the pattern recommended in Working with DataSources in Code.

      To write code in Visual Basic

      Visual Basic
      Copy Code
      Private _scope As EntityClientScope = Program.ClientCache.CreateScope()

      To write code in C#

      C#
      Copy Code
      private EntityClientScope _scope = Program.ClientCache.CreateScope();
    3. Getting Products data from the scope, we create a live view and bind the grid to that view in the form’s constructor:

      To write code in Visual Basic

      Visual Basic
      Copy Code
      _viewProducts =
           (From p In _scope.GetItems(Of Product)()
            Where Not p.Discontinued And p.UnitPrice >= 30
            Order By p.UnitPrice
            Select New With
            {
                p.ProductID,
                p.ProductName,
                p.CategoryID,
                p.Category.CategoryName,
                p.SupplierID,
                .Supplier = p.Supplier.CompanyName,
                p.UnitPrice,
                p.QuantityPerUnit,
                p.UnitsInStock,
                p.UnitsOnOrder
            }).AsDynamic()
       dataGridView1.DataSource = _viewProducts

      To write code in C#

      C#
      Copy Code
      _viewProducts =
      (from p in _scope.GetItems<Product>()
                              where !p.Discontinued && p.UnitPrice >= 30
                              orderby p.UnitPrice
                              select new
                              {
                                  ProductID = p.ProductID,
                                  ProductName = p.ProductName,
                                  CategoryID = p.CategoryID,
                                  CategoryName = p.Category.CategoryName,
                                  SupplierID = p.SupplierID,
                                  Supplier = p.Supplier.CompanyName,
                                  UnitPrice = p.UnitPrice,
                                  QuantityPerUnit = p.QuantityPerUnit,
                                  UnitsInStock = p.UnitsInStock,
                                  UnitsOnOrder = p.UnitsOnOrder
                              }).AsDynamic();
      
      dataGridView1.DataSource = _viewProducts;
      

      In this example, we applied several LiveLinq operators: Where, OrderBy, and Select. We defined our view as containing products that aren’t discontinued and have a unit price of at least 30, and we sorted our view by unit price.

      We chose to store the view in a private field _viewProducts here:

      To write code in Visual Basic

      Visual Basic
      Copy Code
      Private _viewProducts As View(Of Object)

      To write code in C#

      C#
      Copy Code
      private View<dynamic> _viewProducts;

      That is only because we will need it later. If we did not, we could use a local variable for the view.

      Syntactically, the query that we wrote for _viewProducts is just standard LINQ. It could be done without C1DataSource, with standard LINQ to Objects, and the code would be the same, only instead of _scope.GetItems<Product>(), you would use something like ObjectContext.Products. In fact, we will try to do just that in a moment, once we run the project, to compare what we get from standard LINQ with what we get from LiveLinq.

    4. Now run the project. You see that the grid shows the filtered set of products, "expensive" products that aren’t discontinued, in the order that we specified with the columns that we specified. Note also that all columns are modifiable, and you can even add and delete rows in the grid. Also note that you can sort the grid at run time by clicking column headers.

    To appreciate this full data binding support, compare it with what you would get if you did not use C1DataSource, but if you used standard LINQ to Objects instead. It’s easy to compare; just replace _scope.GetItems<Product>() in the code with Program.ObjectContext.Products. Note that you will also need to remove the type C1.LiveLinq.LiveViews.View and use the 'var' keyword instead for it to compile, because it will no longer be a live view. The difference is obvious: with standard LINQ, the data in the grid is read-only, and the grid does not support sorting.

    But live views offer even more great features. Standard LINQ to Objects produces snapshots of the data that cannot reflect changes in the source data, except some simple property changes, and even then under the strict proviso that you don’t utilize a custom Select in your LINQ statement. Live Views, on the other hand, provide dynamic ‘live’ views that automatically reflect changes in their source data. As such, they simplify application development because you can, in most cases, rely on data binding to automate ‘live’ changes in views without the need to synchronize the changes in different parts of the application with code.

    To see that the views are indeed ‘live’, open two forms side-by-side. Run your application and open up the Custom Columns form, which we built in Customizing View, and the Client Side Querying form, which we just built here. Make some changes to a product in the CustomColumns form and observe how they are reflected in the other form. If, for example, you were to increase the UnitCost of a product to above 30, then it would automatically appear in the second form.

    To see another example of how live views automatically synchronize themselves with changes in underlying data, follow these steps:

    1. Add a live view member of the user control class:

      To write code in Visual Basic

      Visual Basic
      Copy Code
      Private _seafoodProductsView As ClientView(Of Product)

      To write code in C#

      C#
      Copy Code
      private ClientView<Product> _seafoodProductsView;
    2. Add the following code to the form’s constructor:

      To write code in Visual Basic

      Visual Basic
      Copy Code
      _seafoodProductsView = _scope.GetItems(Of Product)().AsFiltered(Function(p) p.CategoryID.Value = 8)

      To write code in C#

      C#
      Copy Code
      _seafoodProductsView = _scope.GetItems<Product>().AsFiltered(p => p.CategoryID == 8);
    3. Add two buttons, named btnRaise and btnCut, to the form and add the following handlers to the form’s code :

      To write code in Visual Basic

      Visual Basic
      Copy Code
      Private Sub raiseButton_Click(sender As System.Object, e As System.EventArgs)
      For Each p In _seafoodProductsView
      p.UnitPrice *= 1.2
      Next
      End Sub
      Private Sub cutButton_Click(sender As System.Object, e As System.EventArgs)
      For Each p In _seafoodProductsView
      p.UnitPrice /= 1.2
      Next
      End Sub

      To write code in C#

      C#
      Copy Code
      private void raiseButton_Click(object sender, EventArgs e)
      {
          foreach (var p in _seafoodProductsView)
              p.UnitPrice *= 1.2m;
      }
      private void cutButton_Click(object sender, EventArgs e)
      {
          foreach (var p in _seafoodProductsView)
              p.UnitPrice /= 1.2m;
      }
      
    4. Save, build and run the application. As you press the buttons, notice how seafood products appear in the grid because their unit price is now either greater than or equal to 30 or how they disappear when their unit price falls below 30. All of this happens automatically. You did not have to write any special code to refresh or synchronize the grid.
    5. To see how live views can make almost any GUI-related code easier to write (and less error-prone), let’s add a label that shows the current row count. Without C1DataSource, this would usually be done in a method counting the rows, and that method would have to be called in every place in the code where that count can change. In this example, there would be three such places: on initial load, and in the two methods called when the buttons are pressed, raiseButton_Click and cutButton_Click. So it is not very easy to synchronize display with changing data even in this simple example, not to speak of a real application. Live views make all this synchronization code unnecessary. We already saw how it works for a view containing filtering, ordering, and projection (Where, OrderBy, and Select). It works as well for views containing aggregation operations, such as Count. A little difference here is that regular LINQ Count returns a single number, to which you can’t bind a control, so C1DataSource provides a special operation LiveCount that returns a live view instead of a single number, so you can use it in data binding. We can create this binding with a single line of code:
      labelCount.DataBindings.Add(new Binding("Text", 
      _viewProducts.LiveCount(), "Value"));