Search  
Friday, September 10, 2010 ..:: Articles » CSLA version 2; what's in it for me? ::..   Login
 CSLA version 2; what is in it for me?
Introduction | Business Objects | Simplify UI | Data Binding | ORM | Business rules | N-level undo | Security | Scalability | Localisation | Best practice | Community | License | Links
 
Show as single page

Deliverable: n-level undo

Let us start with the simple 2-level undo that we have already seen in my demo application. This was where the program allowed an undo of changes made to both the customer, as well as any of the customer's order headers.

Firstly the application set things up by instructing the CSLA framework to take a snapshot of the Customer BO, including any imbedded order headers, before allowing the user to gain access to it:

_customer.BeginEdit();

Data at both levels was then turned over to data binding for use by the UI.

customerBindingSource.DataSource = _customer;
customerOrdersBindingSource.DataSource = _customer.Orders;

The user then was allowed to make data entry changes to the customer level data, and it's collection of customer order headers. Data binding updated our Customer BO and the embedded collection of Order BO's. Data binding worked behind the scenes to issue BeginEdit and ApplyEdit instructions at the Order Header level, as the user changed, then departed from, order rows.

Nothing is persisted to the database unless the user presses the “Save” button, which calls the following line of code. The Customer object knows how, and when, to save any changed rows in it's Order collection. The UI can therefore ignore the Order objects, as from it's perspective it is dealing with a Customer object that has an Orders property. The database update is essentially triggered via the following.

customerBindingSource.EndEdit();
customerOrdersBindingSource.EndEdit();
_customer.Save();

If the user wanted to discard the changes, this could be done by pressing the CancelEdit button, which allows us to achieve a 2-level undo with the following instruction. All data, including any changed orders, is reset to the snapshot.

_customer.CancelEdit();

To proceed beyond a 2-level undo we need to extend our application to also open a modal form. The first form can open the modal form, passing it the active grid row's Order BO from the Customer's collection. The modal form will display that order's details, and allow us to update the freight value.

To run this demonstration I opened the main screen, and used it to alter the freight amount of the second order item from the database's original $71.07 to $11.11. I did not press the “save” button, so although the Customer BO has been modified I still had the option of undoing my change.

I then clicked the order's ID link field, opening the modal form showing just the altered order. The freight value showed the changed value of $11.11. I used the modal form to change the freight amount again, this time to $22.22. The change was reflected back into the underlying main form, as both forms are working with the same Order BO. The modal form's “Cancel” button took me back to the modified value of $11.11 which was the value that it 1st saw, but would not take me back to the original $71.07 which was loaded from the database. The modal screen's “cancel” action also caused the underlying main screen's value to be reset to $71.07.

I changed the modal screen's value back to $22.22 again, pressed the modal screen's “save” button, and then closed the form.

The main form regained focus, with the second order line showing the $22.22 which the modal screen had updated into my BO. When I pressed the main form's “Cancel” button the freight amount was reset back to the original $11.11. This action restored us to the original value, wiping out changes made in n-levels (ie. both the main and modal forms).

All of this was achieved without referring back to the database. The database did not receive any of the updates as the main form's “save” button was not pressed. The order details are children of the customer BO. They are obtained from the database by the customer BO, and can only be updated back to the database by the Customer BO.


The code required to achieve this n-level undo capacity is very simple. The main form loads the modal form, passing it the Order BO shown by the current grid row.

private void customerOrdersDataGridView_CellContentClick(object sender,
   DataGridViewCellEventArgs e)
  {
   if (e.ColumnIndex == iDDataGridViewLinkColumn.Index)
   {
    /* close off 1-level undo support for the current grid row
     * implicitly started by .Net data binding */
    customerOrdersBindingSource.EndEdit();

    using (OrderDetailForm ordersForm =
     new OrderDetailForm((Order)customerOrdersBindingSource.Current))
    {
     ordersForm.ShowDialog();
    }
   }
  }

The modal form's constructor is as follows. We really only need focus upon the incoming parameter, and the line where we issue a BeginEdit call against that order. Most of the remainder of the method deals with obtaining the order detail lines for display purposes.

public OrderDetailForm(Order order)
  {
   InitializeComponent();

   _order = order;

   this.readWriteAuthorization1.ResetControlAuthorization();

   this.Text = "Update freight for order number " + _order.Id.ToString();

   _order.BeginEdit();
   orderBindingSource.DataSource = _order;
   try
   {
    OrderLineList _orderLines = OrderLineList.GetOrderLines(_order.Id);
    if (_orderLines != null)
    {
     orderLineListBindingSource.DataSource = _orderLines;
    }
   }
   catch (Csla.DataPortalException ex)
   {
    MessageBox.Show(ex.BusinessException.ToString(),
    "Data load error", MessageBoxButtons.OK,
    MessageBoxIcon.Exclamation);
   }
   catch (Exception ex)
   {
    MessageBox.Show(ex.ToString(),
    "Data load error", MessageBoxButtons.OK,
    MessageBoxIcon.Exclamation);
   }
  }

The remainder of the modal program is as follows. Really, the only point to notice from all this is that the CSLA framework has given us n-level undo without any effort on our part.

private void SaveButton_Click(object sender, EventArgs e)
  {
   /* commit change, then make a new snapshot so that any further changes
    * are undoable.*/  
   orderBindingSource.EndEdit();
   _order.BeginEdit();
  }

  private void CancelButton_Click(object sender, EventArgs e)
  {
   _order.CancelEdit();
   _order.BeginEdit();
  }

  private void OrderDetailForm_FormClosing(object sender, FormClosingEventArgs e)
  {
   _order.CancelEdit();
  }

  private void orderBindingSource_CurrentItemChanged(object sender, EventArgs e)
  {
   SaveButton.Enabled = _order.IsValid;
  }
 }

The n-level undo was achieved via the main form's “cancel” button.

private void cancelButton_Click(object sender, EventArgs e)
  {
   _customer.CancelEdit();
   _customer.BeginEdit();
  }

Business rules | Page 7 of 14 | Security

      

Copyright 2005 by Primos Computer Services   Terms Of Use  Privacy Statement