locked
Communication between screens ? RRS feed

  • Question

  • Hi,

    Here the scenario I wanted to achieve and what I did:

    I want the datagrid content of one screen to be automatically refreshed when a new entity is added through the command bar.

    I created a custom Add Screen CreateNewEmployee for one of my entities with a parameter.

    I overloaded the Add button execute method from the command bar of the datagrid to launch CreateNewEmployee.

    Unfortunately, the ShowCreateNewEmployee method of Application only exposes the parameter. I didn't find how to suscribe to the Saved event.

    I tried to launch the screen another way like below but nothing shows when I click the button.

    Thanks for your help.

     

    Dispatchers.Main.BeginInvoke(() =>
                {
                    CreateNewEmployee newEmployeeScreen = new CreateNewEmployee(this.OfficeLocation.Id);
                    newEmployeeScreen.Details.Commands.Save.ExecuteCompleted += new EventHandler<ExecuteCompletedEventArgs>((sender, e) =>
                    {
                        if (e.Error == null && !e.Cancelled)
                        {
                            this.EmployeeByOfficeAndCapabilityCollection.Details.Commands.Refresh.Execute();
                        }
                    });


                });

     

    Tuesday, September 7, 2010 2:48 AM

Answers

  • You are very close to the behavior of what you want.  The problem with what you have is that the new screen instance is never shown.  After you create the instance of the CreateNewEmployee screen, do the following and then subscribe to the ExecuteCompeleted event:

    IClientApplicationDetails details = this.Application.Details;
    details.ShowScreen(newEmployeeScreen.Details.GetModel().Id, () => newEmployeeScreen, new object[] { this.OfficeLocation.Id });
    
    • Marked as answer by Onlyann Tuesday, September 7, 2010 6:47 AM
    Tuesday, September 7, 2010 5:49 AM

All replies

  • You are very close to the behavior of what you want.  The problem with what you have is that the new screen instance is never shown.  After you create the instance of the CreateNewEmployee screen, do the following and then subscribe to the ExecuteCompeleted event:

    IClientApplicationDetails details = this.Application.Details;
    details.ShowScreen(newEmployeeScreen.Details.GetModel().Id, () => newEmployeeScreen, new object[] { this.OfficeLocation.Id });
    
    • Marked as answer by Onlyann Tuesday, September 7, 2010 6:47 AM
    Tuesday, September 7, 2010 5:49 AM
  • Thank you. This works like a charm.

    You probably already have this in mind for the later versions, but it would be nice to enrich the Application show screen helper with an access to the screen view model events/commands.

    Good work LightSwitch team.

    Tuesday, September 7, 2010 6:45 AM
  • Hello, I found a way to do the refresh in an easier way:

    In the parent, open the screen to add the employee in the common way, Application.ShowCreateNewEmployee ();

    In the child implement the Saved event,

    partial CreateNewEmployee_Saved()
    {
    
    //Lookup for the parent screen
    
    var parentScreen = Application.ActiveScreens.OfType<ParentScreenType>().First();
    
    //Invoke the refresh
    
    parentScreen.Details.Dispatcher.BeginInvoke(() => parentScreen.Details.Commands.Refresh.Execute());
    
    }
    
    I hope this helps :)
    Wednesday, January 5, 2011 11:09 PM
  • What you've shown is another way to do it, but it only works (correctly) under the following conditions:

    • The parent screen has not been closed. If the screen were closed, the First extension method would throw an exception.
    • The parent screen does not allow for multiple instances. If it did, the First extension method would not necessarily return the correct instance.
    Thursday, January 6, 2011 6:56 AM
  • What you've shown is another way to do it, but it only works (correctly) under the following conditions:

    • The parent screen has not been closed. If the screen were closed, the First extension method would throw an exception.
    • The parent screen does not allow for multiple instances. If it did, the First extension method would not necessarily return the correct instance.

    Hey Justin would you mind showing your method again...in full...and in VB if possible?  :)
    Thursday, January 6, 2011 8:50 AM
  • Hello Justin, you are right, it was only for demonstration purposes, now, I'm gonna make it better:

    partial CreateNewEmployee_Saved()
    {
      //Lookup for the parent screen
      foreach (var parentScreen in Application.ActiveScreens.OfType<ParentScreenType>())
      {
         //Invoke the refresh
         parentScreen.Details.Dispatcher.BeginInvoke(() => parentScreen.Details.Commands.Refresh.Execute());
      }
    }
    
    

    Justin, in your second point you talked about the correct parent instance, in this case, all the instances of the parent type are refreshed, but for simple cases it would be fine :)

    I'm not a VB expert, so I need some help to put the code in the vb way

    Thursday, January 6, 2011 4:04 PM
  • Good Stuff Diego!  Ok this seems to work well in VB.  It's intended to be used in the closing code of a details screen that was opened from a search screen.  Since you can only have either 1 or none of a particular search screen open at once..i think it's ok to just call the refresh of that open search screen directly...that is only if it's still open.

     

    Private Sub MyPersonDetailsScreen_Saved()
          If Application.ActiveScreens.OfType(Of MySearchPeopleScreen)().Count > 0 Then
            Dim parentScreen = Application.ActiveScreens.OfType(Of MySearchPeopleScreen)().First
            parentScreen.Details.Dispatcher.BeginInvoke(Sub() parentScreen.Details.Commands.Refresh.Execute())
          End If
          Me.Close(False)
        End Sub

     

    It seems to me that there are at least three "Levels" of open screens.  First you have your basic Top Level Search Screen.  Second You have a details screen of the entities listed in the original search screen.  Then Third you have details of the detail, or even details of details of the detail..etc.  There can be any number of Second or Third Level(and beyond) screens open at a time.

    The above Code seems to work on the save event of Second Level screens - refreshing top level screens only because there can only be 1 or none of them open.  For Third level (and beyond) screens..I'm thinking the "Subscribe" method is best....hopefully Justin will outline that procedure for us again.  Iterating all of the 2nd level or even third level screens might be too costly.  Anyway hope this makes sense to someone.

    Thursday, January 6, 2011 8:18 PM
  • I think that Sheel came up with a great solution that does not require iteration through the active screens nor knowing which screen opened another screen: http://blogs.msdn.com/b/lightswitch/archive/2010/11/17/communicating-across-lightswitch-screens.aspx

    The basic idea is that you create an event on the Application object that represents when an entities of a certain type have been created, removed, etc. Any screen can then subscribe to the event and respond to the action (e.g. refresh a collection of that entity type). Any screen can also raise that event when a save operation has been completed on that screen.

    Thursday, January 6, 2011 11:43 PM
  • Tnks Justin...I'll check it out.
    Thursday, January 6, 2011 11:55 PM
  • I think that Sheel came up with a great solution that does not require iteration through the active screens nor knowing which screen opened another screen: http://blogs.msdn.com/b/lightswitch/archive/2010/11/17/communicating-across-lightswitch-screens.aspx

    The basic idea is that you create an event on the Application object that represents when an entities of a certain type have been created, removed, etc. Any screen can then subscribe to the event and respond to the action (e.g. refresh a collection of that entity type). Any screen can also raise that event when a save operation has been completed on that screen.


    So...thinking about this a little bit...there are built in application events already for entity_insert, update, delete right?  I guess we would have to subscribe to those events?  I wish there was an all encompassing event -  one that triggered when any of those happened...that way we would only have to listen for one event.  In the same regard i wish there was an event that fired when any property of an entity was changed..not just individual properties.  It's great to have the granularity that's in place now but a general event for both situations would also be useful.
    Friday, January 7, 2011 12:09 AM
  • After reading Sheel's blog post - which was great - I am now wondering if we can trigger the event from the Application Data Services Layer instead of the screen saved event.  What if we used entity_inserted, updated, and deleted instead? That way we wouldn't have to  trigger the event on each screen that affects a given entity.  Is there a problem with doing something like because of the multiple tiered architecture?  This would be great because then any time our entity set was changed our lists would automatically refresh.
    Friday, January 7, 2011 7:20 AM
  • Cool got it working using Sheel's method.  But as I'm trying to figure out the best way to do this it's occurring to me that these are the types of decisions the "Systems" guys are supposed to work out....I'm not working on my business logic here....Any chance the LS team can incorporate auto refreshing screens somehow.  Or at least auto generate the events for Entity Set changes that we can easily hook into? If you are working on it please let us know so we don't waste time working on it if the team already has a solution.

    Friday, January 7, 2011 7:54 AM
  • I think that Sheel came up with a great solution that does not require iteration through the active screens nor knowing which screen opened another screen: http://blogs.msdn.com/b/lightswitch/archive/2010/11/17/communicating-across-lightswitch-screens.aspx

    The basic idea is that you create an event on the Application object that represents when an entities of a certain type have been created, removed, etc. Any screen can then subscribe to the event and respond to the action (e.g. refresh a collection of that entity type). Any screen can also raise that event when a save operation has been completed on that screen.


    So...thinking about this a little bit...there are built in application events already for entity_insert, update, delete right?  I guess we would have to subscribe to those events?  I wish there was an all encompassing event -  one that triggered when any of those happened...that way we would only have to listen for one event.  In the same regard i wish there was an event that fired when any property of an entity was changed..not just individual properties.  It's great to have the granularity that's in place now but a general event for both situations would also be useful.
    Hello, you could create a domain service in order to expose the entities with LinqToSql or Entity Framework, you could override the SubmitChanged or SaveChanges method in the datacontext, so you could have access to the entities inserted, updated or deleted in only one place, within lightwitch you could use a this WCF Ria Services datasource instead of a Database as data source.

    In my current app I need to add an audit log entry for each entity inserted, updated or deleted, I did it with a WCF Ria Services Datasource an Entity Framework, because implementing the audit log entry within each lightswitch entity event: entity_inserted, entity_updated, entity_deleted were so tedious.

    Thinking in your other two post, all this action happens on the server site, I don't think that is possible to notify back the client site and refresh automatically the UI collections, because we are in a multi-tier architecture, but with the article found by Justin at http://blogs.msdn.com/b/lightswitch/archive/2010/11/17/communicating-across-lightswitch-screens.aspx we have a easy way to implement UI logic for entities inserted, updated or deleted in the lightswitch client side.
    Friday, January 7, 2011 3:54 PM
  • Hello, you could create a domain service in order to expose the entities with LinqToSql or Entity Framework, you could override the SubmitChanged or SaveChanges method in the datacontext, so you could have access to the entities inserted, updated or deleted in only one place, within lightwitch you could use a this WCF Ria Services datasource instead of a Database as data source.

    In my current app I need to add an audit log entry for each entity inserted, updated or deleted, I did it with a WCF Ria Services Datasource an Entity Framework, because implementing the audit log entry within each lightswitch entity event: entity_inserted, entity_updated, entity_deleted were so tedious.

    Thinking in your other two post, all this action happens on the server site, I don't think that is possible to notify back the client site and refresh automatically the UI collections, because we are in a multi-tier architecture, but with the article found by Justin at http://blogs.msdn.com/b/lightswitch/archive/2010/11/17/communicating-across-lightswitch-screens.aspx we have a easy way to implement UI logic for entities inserted, updated or deleted in the lightswitch client side.

    Good Points Diego..seems like we are on the exact same page.  Hopefully the LS team can make this easier somehow.  I'm pretty sure it would be on the top of the list of things people expect when using these apps.
    Friday, January 7, 2011 7:50 PM
  • Diego/Gberg/Justin,

    Yes, I would also like to see a built-in way of LS doing this. It seems a natural part of any "application framework". In fact *anything* that we find ourselves doing over & over seems like a good candidate for a framework to handle.

    The LS team have done a marvelous job of doing that for so many things already, letting us concentrate on writing business code instead of tedious plumbing code. To me, this refreshing issue falls in the plumbing code area. I certainly hope they keep identifying areas like this and create ways to handle them in the framework for us.

    Yann

    PS - the "onlyann" profile is NOT me, nor has it got anything to do with me

    Friday, March 4, 2011 11:29 PM
  • Should this work also in Beta 2?

    Application.ActiveScreens.OfType<SomeParentScreen>().FirstOrDefault()
    Is always returning null
    Monday, March 21, 2011 5:08 PM
  • Yeah....i am having problems with this method as well as Sheel's other event driven method. 
    Monday, March 21, 2011 6:29 PM
  •  

    Hi all

     

    In this blog

     

    http://blogs.msdn.com/b/lightswitch/archive/2010/11/17/communicating-across-lightswitch-screens.aspx

     

     Sheel Shah explains in clear and simple as in LightSwitch Refresh. And it works perfect.

     

    Jaime

     

    Saturday, June 25, 2011 11:07 PM