Creating a Custom Add or Edit Dialog (Sheel Shah)

Creating a Custom Add or Edit Dialog (Sheel Shah)

Rate This
  • Comments 26

LightSwitch provides built-in functionality quickly add or edit data in a grid or list.  Unfortunately this modal dialog is not customizable.  In more complex data entry scenarios, the built-in dialogs may not fulfill your customer's needs.  There are a couple of options in this situation.

  1. Provide specific screens for adding/editing records.  For extremely complex data entry or manipulation scenarios, this may be the best option.  However, your application will need to manually manage refreshing data on the list or grid screens.
  2. Replace the built-in modal dialog with your own.  This is ideal for quick edit or add functionality but does require a bit of code to achieve.

This article will describe how to provide a customized dialog for adding or editing records in a grid.

Getting Setup

Create a new LightSwitch application.  Add a Customer table with the following fields:

  • FirstName (String, Required)
  • MiddeInitial (String, Not Required)
  • LastName (String, Required)
  • PhoneNumber (Phone Number, Required)

clip_image002

Create a new Editable Grid screen for Customers.

clip_image002[9]

Define the Modal Window

On the Editable Grid screen,  right click on the top-most item and select "Add Group".

clip_image002[11]

On the group, select the dropdown next to "Rows Layout" and change this to "Modal Window".   Select the "Add"  button underneath the modal window and choose Selected Item.  This will display the currently selected customer in the modal window.   This view can now be customized as necessary.

clip_image003

By default, a modal window group will display a button on the screen.  This button can be used to launch the window.  In our scenario, we don't want this default button display - instead, we'd like to launch the modal window whenever the user clicks the Add or Edit button in a list or grid.   Select the modal window and in the properties grid set the "Show Button" property to false.  We can also change the name of the group to CustomerEditDialog.

clip_image004

Modifying the Grid’s Add/Edit Functionality

We can now override the grid's add and edit buttons to instead launch our modal window.   Open the Command Bar for the data grid, right click on the "Add…" button and select "Override Code".

clip_image002[13]

Add the following code for the Execute and CanExecute methods.  This code will add a new record to the collection and open the modal window. 

Private Sub gridAddAndEditNew_CanExecute(ByRef result As Boolean)

    result = Me.Customers.CanAddNew()

End Sub

 

Private Sub gridAddAndEditNew_Execute()

    Dim newCustomer As Customer = Me.Customers.AddNew()

    Me.Customers.SelectedItem = newCustomer

    Me.OpenModalWindow("CustomerEditDialog")

End Sub

Similarly, right click on the "Edit…" button in the screen editor and select "Override Code"  Add the following code.

Private Sub gridEditSelected_CanExecute(ByRef result As Boolean)

    result = Me.Customers.CanEdit AndAlso Me.Customers.SelectedItem IsNot Nothing

End Sub

 

Private Sub gridEditSelected_Execute()

    Me.OpenModalWindow("CustomerEditDialog")

End Sub

Test the Application

Run the application and click on the Add or Edit buttons in the Editable Customer Grid.  This should launch our custom dialog.

clip_image001

Unfortunately, the dialog we've created is quite limited in functionality.  It does not include the Ok and Cancel buttons of the built-in dialog.  It also does not update its title based on whether it is editing or creating a customer.

Providing Additional Functionality

In the screen designer, right click on the Modal Window and select "Add Button...".     Choose "New Method" and name the method EditDialogOk.  In the property sheet, change the Display Name of the button to just Ok.

clip_image002[15]

clip_image002[17]

Add a similar button called EditDialogCancel.   Again, change the display name of the modal window to just Cancel.

clip_image002[19]

Double click on the Ok button to add some code.   We will add some code to close the modal dialog when either Ok or Cancel is pressed.

Private Sub EditDialogOk_Execute()
    Me.CloseModalWindow("CustomerEditDialog")
End Sub
 
Private Sub EditDialogCancel_Execute()
    Me.CloseModalWindow("CustomerEditDialog")
End Sub

This code simply closes the dialog when the user presses Cancel.   This is not ideal.    When Cancel is pressed, we'd like new records removed and changes to existing records reverted.  This is possible, but requires a fair bit of code.  The following helper class will provide this functionality.

Public Class DialogHelper
    Private _screen As Microsoft.LightSwitch.Client.IScreenObject
    Private _collection As Microsoft.LightSwitch.Client.IVisualCollection
    Private _dialogName As String
 
    Private _isEditing As Boolean = False
    Private _entity As IEntityObject

Public Sub New (ByVal visualCollection As Microsoft.LightSwitch.Client.IVisualCollection,
                    ByVal dialogName As String)
        _screen = visualCollection.Screen
        _collection = visualCollection
        _dialogName = dialogName
    End Sub
 
    Public Sub InitializeUI()
            'This code may not work in Beta 2.  Fixed in final release.  
    
AddHandler
_screen.FindControl(_dialogName).ControlAvailable,
            Sub(sender As Object, e As ControlAvailableEventArgs)
                Dim childWindow As System.Windows.Controls.ChildWindow = e.Control
         AddHandler childWindow.Closed, 
Sub(s1 As Object, e1 As EventArgs)
                        If _entity IsNot Nothing Then
          DirectCast(_entity.Details, IEditableObject).CancelEdit()
                        End If
                    End Sub
            End Sub
    End Sub
 
    Public Function CanEditSelected() As Boolean
        Return _collection.CanEdit() AndAlso (Not _collection.SelectedItem Is Nothing)
    End Function
 
        Public Function CanAdd() As Boolean
            Return _collection.CanAddNew()
        End Function
        Public Sub AddEntity()
            _isEditing = False
            _collection.AddNew()
            _screen.FindControl(_dialogName).DisplayName = "Add " + 
_collection.Details.GetModel.ElementType.Name
            BaseOpenDialog()
        End Sub
 
        Public Sub EditSelectedEntity()
            _isEditing = True
            _screen.FindControl(_dialogName).DisplayName = "Edit " + 
_collection.Details.GetModel.ElementType.Name
            BaseOpenDialog()
        End Sub
 
        Private Sub BaseOpenDialog()
            _entity = _collection.SelectedItem()
            If _entity IsNot Nothing Then
Dispatchers.Main.Invoke(Sub()
                   DirectCast(_entity.Details, IEditableObject).EndEdit()
   DirectCast(_entity.Details, IEditableObject).BeginEdit()
                End Sub)
                _screen.OpenModalWindow(_dialogName)
            End If
        End Sub
 
        Public Sub DialogOk()
            If _entity IsNot Nothing Then
Dispatchers.Main.Invoke(Sub()
                   DirectCast(_entity.Details, IEditableObject).EndEdit()
              End Sub)
         _screen.CloseModalWindow(_dialogName)
            End If
        End Sub
 
        Public Sub DialogCancel()
            If _entity IsNot Nothing Then
                Dispatchers.Main.Invoke(Sub()
                     DirectCast(_entity.Details, IEditableObject).CancelEdit()
                End Sub)
                If _isEditing = False Then
                    _entity.Delete()
                End If
                _screen.CloseModalWindow(_dialogName)
            End If
        End Sub
End Class

Using the Helper Class

First, we'll need to add the class to our project.  Right click on the application in the solution explorer and select "View Application Code (Client)".   Paste the code from above beneath the Application class.    This will also require importing the Microsoft.LightSwitch.Threading namespace.

Imports Microsoft.LightSwitch.Threading
Namespace LightSwitchApplication
 
    Public Class Application
 
    End Class
 
    Public Class DialogHelper
        'Code from above
    End Class
End Namespace

This helper library requires a reference to an additional library.  Select the application in Solution Explorer and switch to File View.   Right click on the Client application and select "Add Reference".   Select the "System.Windows.Controls" component and press Ok.

On our existing grid screen for Customer, we'll need to initialize and use this helper class.  The code for many of our existing methods is replaced by calls to the helper class.  The final code for our screen is shown below.

Public Class EditableCustomersGrid
    Private customersDialogHelper As DialogHelper

Private Sub
EditableCustomersGridOld_InitializeDataWorkspace(
saveChangesTo As System.Collections.Generic.List(Of Microsoft.LightSwitch.IDataService))
            customersDialogHelper = New DialogHelper(Me.Customers, "CustomerEditDialog")
    End Sub
 
        Private Sub EditableCustomersGridOld_Created()
            customersDialogHelper.InitializeUI()
        End Sub
 
        Private Sub gridAddAndEditNew_CanExecute(ByRef result As Boolean)
            result = customersDialogHelper.CanAdd()
        End Sub
 
        Private Sub gridAddAndEditNew_Execute()
            customersDialogHelper.AddEntity()
        End Sub
 
        Private Sub gridEditSelected_CanExecute(ByRef result As Boolean)
            result = customersDialogHelper.CanEditSelected()
        End Sub
 
        Private Sub gridEditSelected_Execute()
            customersDialogHelper.EditSelectedEntity()
        End Sub
 
        Private Sub EditDialogOk_Execute()
            customersDialogHelper.DialogOk()
        End Sub
 
        Private Sub EditDialogCancel_Execute()
            customersDialogHelper.DialogCancel()
        End Sub
 End Class

Run the Application

Run the application again.  Click on the "Add" button for the grid.  This will open our modal dialog with the title appropriately updated.  If we click on the "Cancel" button, the newly added record will be removed.  Similarly,  if a record is being edited and "Cancel" is clicked, the changes will be reverted.

clip_image001[6]

While a little involved, this technique can be applied to any of your other screens.  If you have more than one list on a screen, multiple custom dialogs can be added.   The DialogHelper class utilizes some of the more advanced API options available within LightSwitch.  We’re also planning on wrapping this sample into a screen template that will automatically generate the modal window and code that is needed.

- Sheel

Leave a Comment
  • Please add 6 and 8 and type the answer here:
  • Post
  • vsls team hi

    for real this thinks is so much harder for any one

    in the time all in microsoft history create business application as a easy way to create business application ands now become harder to add a button

    thinks again

    ayman fouad fb.com/submarin64x

  • merci beaucoup !!!!!

    c'est simple et bien expliqué

    Thanks a lot

  • Sometimes you want to initialize the entity so I added this overload:

           Public Sub AddEntity(initialEntity As Object)

               _isEditing = False

               _collection.SelectedItem = initialEntity

               _screen.FindControl(_dialogName).DisplayName = "Add " +

                    _collection.Details.GetModel.ElementType.Name

               BaseOpenDialog()

           End Sub

    In the caller I just do:

           Private Sub StudentsByFacilityId1AddAndEditNew_Execute()

               Dim newStudent As New Student

               newStudent.Facility = ppvFacility

               GenericDialogHelper.AddEntity(newStudent)

           End Sub

  •  public class DialogHelper

       {

       private Microsoft.LightSwitch.Client.IScreenObject _screen;

       private Microsoft.LightSwitch.Client.IVisualCollection _collection;

       private string _dialogName;

       private bool _isEditing = false;

       private IEntityObject _entity;

       public DialogHelper(Microsoft.LightSwitch.Client.IVisualCollection visualCollection, string dialogName)

       {

       _screen = visualCollection.Screen;

       _collection = visualCollection;

       _dialogName = dialogName;

       }

       public void InitializeUI()

       {

       //This code may not work in Beta 2.  Fixed in final release.  

       _screen.FindControl(_dialogName).ControlAvailable += (object sender, ControlAvailableEventArgs e) =>

       {

       System.Windows.Controls.ChildWindow childWindow = (ChildWindow)e.Control;

                   childWindow.HasCloseButton = false;

       childWindow.Closed += (object s1, EventArgs e1) =>

       {

       if (_entity != null) {

       ((IEditableObject)_entity.Details).CancelEdit();

       }

       };

       };

       }

       public bool CanEditSelected()

       {

       return _collection.CanEdit && ((_collection.SelectedItem != null));

       }

       public bool CanAdd()

       {

       return _collection.CanAddNew;

       }

       public void AddEntity()

       {

       _isEditing = false;

       _collection.AddNew();

       _screen.FindControl(_dialogName).DisplayName = "Add " + _collection.Details.GetModel().ElementType.Name;

       BaseOpenDialog();

       }

       public void EditSelectedEntity()

       {

       _isEditing = true;

       _screen.FindControl(_dialogName).DisplayName = "Edit " + _collection.Details.GetModel().ElementType.Name;

       BaseOpenDialog();

       }

       private void BaseOpenDialog()

       {

       _entity = (IEntityObject)_collection.SelectedItem;

       if (_entity != null) {

       Dispatchers.Main.Invoke(() =>

       {

       ((IEditableObject)_entity.Details).EndEdit();

       ((IEditableObject)_entity.Details).BeginEdit();

       });

       _screen.OpenModalWindow(_dialogName);

       }

       }

       public void DialogOk()

       {

       if (_entity != null && _entity.Details.ValidationResults.Errors!=null) {

       Dispatchers.Main.Invoke(() => { ((IEditableObject)_entity.Details).EndEdit(); });

       _screen.CloseModalWindow(_dialogName);

       }

       }

       public void DialogCancel()

       {

       if (_entity != null) {

       Dispatchers.Main.Invoke(() => { ((IEditableObject)_entity.Details).CancelEdit(); });

       if (_isEditing == false) {

       _entity.Delete();

       }

       _screen.CloseModalWindow(_dialogName);

       }

       }

      }

  • VSLS2011 is ease

    Private Sub EditDialogCancel_Execute()

      Me.Customers.SelectedItem.Delete();

      Me.CloseModalWindow("CustomerEditDialog");

    End Sub

  • Thanks Sheel for this great DialogHelper class.  I have a little feedback with a problem I'm facing.

    When the the "Add Entity" dialog is open and the user presses the escape key, the new entity created will remain as it is. The DialogCancel() sub works so I tried to add the lines around "_entity.Delete()" to the InitializeUI() sub.  

    Unfortunately I get the error "It is not valid to call Execute() on a different Dispatcher than the ExecutableObject's Logic Dispatcher".  I believe is something to do with a different thread and I can't figure out a solution.

  • I just found a post by Yann that solves my problem.  Here's the link

    "Improved Modal Window Helper Class (based on Sheel's Article 'Creating a Custom Add Or Edit Dialog')"

    social.msdn.microsoft.com/.../138464dd-f38e-48b6-a610-28279418b238

  • perfect code ,,, tks

  • Would appreciate if the code would be in C#

  • Will also appreciate code in C# please

  • Thank you for this great example.

    Is there a way to disable the Enter key because the Enter key triggers the close event by default !!!  

  • I'm having a problem when I click the OK button on the modal dialog. If I enter no info in the dialog and I press OK, none of the validation errors appear, it just closes and the record in the datagrid stays in the datagrid with the empty fields. I'd like the dialog to stay opened and show the validation errors, even when the user clicks ok.

  • Anyone found the work around for Ray and Markus's problem mentioned above?

  • Anyone knows how to provide specific screens for adding/editing records? Because the built-in modal dialog don´t let me add new child records at the same time I’m adding the main record. I created a screen that let me do that but I don´t know how to pass the parent Id to the child so I don´t have to complete it manually

  • Here's a link to a page where someone translated into c#, and not only partially like yann...

    tejana.wordpress.com/.../creating-a-custom-add-or-edit-dialog-in-lightswitch-c-beta2

Page 1 of 2 (26 items) 12