Creating reusable modal screens

Warning: this approach works for Out-of-browser applications, but requires this workaround to work in “in-browser” Silverlight clients.

Update (November 14th 2012): download a code sample that contains this hack.

It’s a great honor to write the Leading LightSwitch column in MSDN magazine.  There’s a number of huge differences between my blog and the column that I have come to love.  For example, my blog has no ‘filter’, I can write what I want, when I want it, which often explodes right back at me.  An article in the Leading LightSwitch column however, is actually previewed by an entire team of people, ranging from community members volunteering to do the technical reviews (thanks Michael to help me out this month!!), as professional editors that guard the well-formedness (they would for example make sure I don’t use words like “well-formedness” :-))

Because of the “hacky” nature, the team & I decided to cut out some parts of my proposal this month.  In this blog post, you’ll find one tale that didn’t make the cut…  If you enjoyed it, make sure to keep an eye on this month’s  Leading LightSwitch column in MSDN magazine, because there’s plenty tales of client-side customization techniques coming in the next article!!!

Creating reusable modal screens

Out of all my customers, I definitely value Nancy the most.  Nancy runs a small but lucrative online gift shop from a small office downtown, where she works with her husband and five employees.  Nancy’s the kind of person that wants everything in her company to work smooth and be optimized for her business process, and thus closely involved in the application development process.  She couldn’t be more opposite to Hank, in every possible way, including her knowledge of IT.

When I showed her LightSwitch for example, she immediately grasped how a new OData-based backend would help to align all of the applications she uses.

Over the 6 weeks that we have been working together Nancy and the people in the office (“working for” would hardly describe our relationship), I spent quite some days just coding away on-site, so I could ask questions if I needed to, when I needed to, and so she can learn a bit of LightSwitch so she can do the modifications in the future.

One day, a question of her caught me completely off guard.

When working with data, it is great how easy it is to model CRUD operations (create, read, update or delete) with LightSwitch, but it’s not all CRUD in real life.  Sometimes, you need to execute a specific command instead.  For example, when a customer phones to Nancy’s office, she wants to look up the customer and register a ticket.

Registering a ticket is a business process tied to this specific use case, not to be mistaken with the CRUD operation of creating a ticket (entity).  When a ticket is registered, an email is sent to the customer with confirmation, a push notification is done to Nancy’s legacy CRM, a reminder is added to her online calendar… To model these commands in LightSwitch it pays off to seriously study the command table pattern.  In the client, you’ll sometimes need a specific screen to provide some specific data for a command, which in many cases makes sense to be a modal screen.

In this case, where I was coding away on Nancy’s application, I was adding a Modal Window inside the customer list and details screen, when Nancy happened to look over my shoulder.

“What ya doin?” she asked.

I explained how Modal Windows are modeled in LightSwitch.  Basically, you take any group control inside a screen, and change it from a Rows Layout (or control is used) to a Modal Window.

Figure 13: change any group layout control to a Modal Window

 

From code, you can then open that modal window whenever you need it.  These modal screens are often required to help with specific commands.

She countered my explanation though: “That makes no sence at all.”

“You’re working in a great IDE that has a really effective Screen Designer, yet you cannot create reusable modal screens for your commands, that one could just call from any other screen?”  The truth was paralyzing, did I really encounter something that simply can’t be done in LightSwitch?

I was lying awake that night thinking about how I could overcome this challenge.  A long time ago, I discovered that the LightSwitch framework has a class called the ScreenChildWindow, which you can use to show custom modal dialogs.  I also knew that for each screen that you design in the Screen Designer, LightSwitch generates a ViewModel class that implements the IScreenObject interface.  So all I’d really need to do, is to find a way to ask LightSwitch to serve me a View for each ViewModel I need, then use that View as the content of my custom ScreenChildWindow.

I got out of bed, fired up my pc and opened the solution that holds Nancy’s application.  The answer to my problem was staring me in the face.  Literally…

I was working on a custom shell for her application, a process in which you’ll constantly talk to the ServiceProxy.  The ServiceProxy has a property called the ScreenViewService, which has only one method…

Figure 14: the ServiceProxy’s ScreenViewService can serve a View for any ViewModel

This was exactly what I need!

To reenact this story yourself, all you need is to add a new Silverlight User Control to the LightSwitch client application, called MyModalWindow.  This control will act as the modal ‘hosting’ window for a screen.  If you want to give it a Cosmopolitan look, you can replace the XAML with:

<shellUtils:ScreenChildWindow x:Class="LightSwitchApplication.MyModalWindow"

  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

  xmlns:ctls="clr-namespace:Microsoft.LightSwitch.Cosmopolitan.Presentation.Controls;assembly=Microsoft.LightSwitch.Cosmopolitan.Client"
  xmlns:shellUtils ="clr-namespace:Microsoft.LightSwitch.Runtime.Shell.Framework;assembly=Microsoft.LightSwitch.Client"  

  xmlns:shelHelpers="clr-namespace:Microsoft.LightSwitch.Runtime.Shell.Helpers;assembly=Microsoft.LightSwitch.Client"      

  mc:Ignorable="d"

  d:DesignHeight="300" d:DesignWidth="400"

  Title="{Binding Screen.DisplayName}"

  >

    <shellUtils:ScreenChildWindow.Resources>

      <ResourceDictionary>

        <ResourceDictionary.MergedDictionaries>

          <ResourceDictionary Source="/Microsoft.LightSwitch.Cosmopolitan.Client;component/Presentation/Themes/CosmopolitanTheme.xaml"/>

          <ResourceDictionary Source="/Microsoft.LightSwitch.Cosmopolitan.Client;component/Presentation/Shells/BasicStyles.xaml"/>
          <ResourceDictionary Source="/Microsoft.LightSwitch.Cosmopolitan.Client;component/Presentation/Shells/CommandResources.xaml"/>
          <ResourceDictionary Source="/Microsoft.LightSwitch.Cosmopolitan.Client;component/Presentation/Shells/NavigationResources.xaml"/>

          <ResourceDictionary Source="/Microsoft.LightSwitch.Cosmopolitan.Client;component/Presentation/Shells/ScreenResources.xaml"/>

        </ResourceDictionary.MergedDictionaries>

      </ResourceDictionary>

    </shellUtils:ScreenChildWindow.Resources>

    <Grid>

      <Grid.RowDefinitions>

        <RowDefinition Height="*" />

        <RowDefinition Height="Auto" />

        <RowDefinition Height="Auto" />

      </Grid.RowDefinitions>

        <ContentPresenter x:Name="TheWindow" Grid.Row="0" Content="{Binding RootUI}" />

        <Border Grid.Row="2" Background="{StaticResource RibbonBackgroundBrush}">

          <ctls:OverflowControl 

            ItemsSource="{Binding ShellCommands}"

            ItemTemplate="{StaticResource ScreenCommandTemplate}"

            OverflowTemplate="{StaticResource ScreenCommandsOverflowTemplate}"

            HorizontalAlignment="Center"

            Margin="0"/>

        </Border>

     </Grid>

</shellUtils:ScreenChildWindow>

Figure 15: the XAML of the ScreenChildWindow

 

In the code-behind, copy these three classes:

using System.Collections.Generic;

using System.Linq;

using Microsoft.LightSwitch.Client;

using Microsoft.LightSwitch.Client.Implementation.Internal;

using Microsoft.LightSwitch.Presentation.Internal;

using Microsoft.LightSwitch.Runtime.Shell.View;

using Microsoft.LightSwitch.Sdk.Proxy;

using Microsoft.VisualStudio.ExtensibilityHosting;

namespace LightSwitchApplication

{

  public partial class MyModalWindow : Microsoft.LightSwitch.Runtime.Shell.Framework.ScreenChildWindow

  {

    private ModalCall call;

    public MyModalWindow(ModalCall call)

    {

       this.call = call;

       this.DataContext = this.call.ModalChildView;

       InitializeComponent();

       this.Closing += MyModalWindow_Closing;

     }

    void MyModalWindow_Closing(

      object sender, System.ComponentModel.CancelEventArgs e)

    {

      ModalHelper.CloseModalWindow(this.call, false);

    }

  }

  public class ModalCall

  {

    public IScreenObject CallerViewModel { get; private set; }

    public IScreenObject ModalChildViewModel { get; private set; }

    public IPresentationScreenView ModalChildView { get; private set; }

    public IPresentationScreenView CallerView { get; private set; }

    public MyModalWindow ModalHostView { get; private set; }

    public ModalCall

      (IScreenObject callerViewModel, IScreenObject modalChildViewModel)

    {

      this.CallerViewModel = callerViewModel;

      CallerView = ScreenViewService.GetScreenView(callerViewModel)

        as IPresentationScreenView;

      this.ModalChildViewModel = modalChildViewModel;

      ScreenViewManager.LoadScreen(modalChildViewModel);

      ModalChildView = ScreenViewService.GetScreenView(modalChildViewModel)

        as IPresentationScreenView;

       ModalHostView = new MyModalWindow(this);

    }

    private static IScreenViewService ScreenViewService

    {

      get

        {

          return ServiceProxy.ScreenViewService;

        }

    }

    private static IScreenViewManager ScreenViewManager

    {

      get

      {

        return ScreenViewService as IScreenViewManager;

      }

    }

    private static IServiceProxy serviceProxy;

    private static IServiceProxy ServiceProxy

    {

      get

      {

        // Get the service proxy that provides access to the needed LightSwitch services.

        if (null == serviceProxy)

          serviceProxy =  VsExportProviderService.GetExportedValue<IServiceProxy>();

        return serviceProxy;

      }

    }

  }

  public static class ModalHelper

  {

    private static List<ModalCall> calls = new List<ModalCall>();

    public static void ShowModalWindow

      (IScreenObject caller, IScreenObject childToMakeModal)

    {

      ModalCall modalCall = new ModalCall(caller, childToMakeModal);

      Microsoft.LightSwitch.Threading.Dispatchers.Main.BeginInvoke(

        () =>

        {

          if (modalCall.ModalChildView != null)

          {

            calls.Add(modalCall);

            modalCall.CallerView.BeginModal(modalCall.ModalHostView);

            modalCall.ModalHostView.Show();

          }

        }

      );

    }

    public static void CloseModalWindow(IScreenObject modalWindowToClose)

    {

      CloseModalWindow(

        Calls

        .Where(c =>

          c.ModalChildViewModel == modalWindowToClose).FirstOrDefault()

        , true);

    }

    public static void CloseModalWindow(ModalCall call, bool closeHostView)

    {

      if (call != null && calls.Remove(call))

      {

        call.CallerView.EndModal(call.ModalHostView);

        if (closeHostView)

          call.ModalHostView.Dispatcher.BeginInvoke(

            () =>

              call.ModalHostView.Close()

         );

      }

    }

  }
}

Figure 16: the c# code that will help to show modal dialogs

 

The class called MyModalWindow is the code-behind of the user control.  It does nothing more than binding the datacontext to the ViewModel that’s passed as an argument in the constructor, and add an event handler that lets a ModalHelper know in case the user pressed the X in the top of the modal dialog to close the screen.

The class called ModalCall takes two ViewModels in (both the calling ViewModel as the ViewModel that should be the content of the modal screen), asks the ScreenViewService to serve the corresponding views, and instantiates a new MyModalWindow with the View of the modal screen as the content.

The ModalHelper class helps the modal process by keeping track of which screen opened which, and which screen should be closed.

You can now use the LightSwitch screen designer to create any screen you want, without writing any XAML, just like you’ve gotten used to.

Figure 17: the View that can now be used as a reusable modal window

One caveat is that the default Close command, that you can add to the Screen Command Bar, won’t work anymore, so make sure it’s set to Not Visible, along with the Save and Refresh commands that won’t make sense in this screen, since it’s not bound to actual data.  Closing this modal screen has to be done from the code in the Register, RegisterHighPrio or Discard screen commands instead, as in:

using System;

namespace LightSwitchApplication

{

  public partial class RegisterNewTicket

  {

    partial void RegisterNewTicket_Created()

    {

      this.OpenedDate = DateTime.Now;

    }

    partial void Register_Execute()

    {

      // Send your command to the server here,

      // then close this modal dialog

      ModalHelper.CloseModalWindow(this);

    }

    partial void RegisterHighPrio_Execute()

    {

      // Send your high prio command to the server here,

      // then close this modal dialog

      ModalHelper.CloseModalWindow(this);

    }

    partial void Discard_Execute()

    {

      // Simply close this modal dialog

      ModalHelper.CloseModalWindow(this);

    }

  }

}

Figure 18: closing the modal window by calling the ModalHelper class

 

After this initial effort of creating a User Control and some helper classes, you can now call this modal dialog from any screen you’d like.  For example, in my customers List and Details screen, I added a new Screen Command called “RegisterTicket”.  To edit the code, right-click it in the Screen Editor.

Figure 19: edit the Execute code for any button

And use that extension point to open the modal screen, which has to be done on the main dispatcher’s thread…

namespace LightSwitchApplication

{

  public partial class CustomersListDetail

  {

    partial void RegisterTicket_CanExecute(ref bool result)

    {

      result = this.Customers.SelectedItem != null;

    }

    partial void RegisterTicket_Execute()

    {

      int currentCustomerId = this.Customers.SelectedItem.Id;

      string currentCustomerName = this.Customers.SelectedItem.FullName;

      Microsoft.LightSwitch.Threading.Dispatchers.Main.BeginInvoke(() =>

      {

        RegisterNewTicket newTicketModalDialogViewModel

          = RegisterNewTicket.CreateInstance();

        newTicketModalDialogViewModel.CustomerId = currentCustomerId;

        newTicketModalDialogViewModel.CustomerName = currentCustomerName;

        ModalHelper.ShowModalWindow(

          this, //the caller, which will be 'greyed out'

          newTicketModalDialogViewModel //the modal dialog VM

        );

      }

      );

    }

  }

}

Figure 20: from that button, open a new modal dialog

 

When the application is running, the customers screen shows the new command.

Figure 21: the “Register Ticket” command is now visible in the action bar

When you click on the Register Ticket icon, the modal window appears…

Figure 22: clicking the “Register Ticket” action opens a modal dialog

The very next morning I paid Nancy a quick visit to show her my marvelous hack.  The solution is simple, yet effective, and I can now use my beloved Screen Designer to design reusable modal screens.

Nancy was smiling right back at me.  It’s awesome when a customer is interested in the technical side of the story, even more so when it actually makes her smile.

“Good, because less duplication means you’ll cost me less.”

Errgh, yes, that too…

About these ads

54 thoughts on “Creating reusable modal screens

  1. wow, cant wait to try this!
    btw. one question, or maybe two: you created custom shell for this app, how you avoid errors like “It is not valid to call ExecuteAsync() because CanExecuteAsync is false.”, cause im banging with my head against a wall with that error for more than few days.. it hurts.. :)
    is there some kind of magic behind it? im thinking that im missing something obvious..

    and second is: can i use EME in my shell extension (like EME to be part of my extension)? thanks!

    cheers and keep a good work!

    Kivito

    • Hey Kivito!
      Thank mate, glad you enjoyed it!

      The shell & theme are the Cosmopolitan shell & theme, the new defaults for a LightSwitch client in the 2012 RC edition…

      I’ve seen your post about this on the forum, but never answered because I never ran into that problem. I am however planning on writing out a really long number of posts on creating a custom shell (it is such a popular subject but very few succeed :-( ) but I’m waiting 2 more months untill the RTM version is out.

      Secondly, yes you can use EME in your shell extension, I would be honored. All throughout EME, I have been really careful about not introducing breaking change in the API, so that for example your extension will never break if I release a newer version. Do check this post: http://social.msdn.microsoft.com/Forums/en-US/lsextensibility/thread/3e75980b-2ce3-4e22-be13-43109d871975 . In your extension, you can create a dependence on EME. I suggest putting the “max version” on “2.0”, because the next version of EME will be a total re-write, perhaps (most likely) making our exensions incompatible for a little while.

      Keep rocking LS, you’re doing great!

      Cheers

      Jan

    • I ran into the same problem. I fixed it by wrapping the call inside a BeginInvoke()
      if (call != null && calls.Remove(call))
      {
      Microsoft.LightSwitch.Threading.Dispatchers.Main.BeginInvoke(() =>
      call.CallerView.EndModal(call.ModalHostView));
      if (closeHostView)
      call.ModalHostView.Dispatcher.BeginInvoke(
      () =>
      call.ModalHostView.Close()
      );
      }

  2. I tried this with VS 2012 RC and when the Modal Box appears, there is nothing in it. I see the Screen’s InitializeDataWorkspace firing but no controls seem to render. Any idea what I’m doing wrong?

    Thanks,
    MikeH

    • Here’s a litle more info…

      Looks like there’s an error being thrown during the InitializeComponent() call in the MyModalWindow(Modal call) constructor:

      System.Windows.Data Error: Cannot get ‘Screen’ value (type ‘Microsoft.LightSwitch.Client.IScreenObject’) from ‘Microsoft.LightSwitch.Presentation.Implementation.Screens.PresentationScreenView’ (type ‘Microsoft.LightSwitch.Presentation.Implementation.Screens.PresentationScreenView’). BindingExpression: Path=’Screen.DisplayName’ DataItem=’Microsoft.LightSwitch.Presentation.Implementation.Screens.PresentationScreenView’ (HashCode=58483472); target element is ‘LightSwitchApplication.MyModalWindow’ (Name=”); target property is ‘Title’ (type ‘System.Object’).. System.MethodAccessException: Attempt by method ‘System.Windows.CLRPropertyListener.get_Value()’ to access method ‘Microsoft.LightSwitch.Presentation.Implementation.Screens.PresentationScreenView.get_Screen()’ failed.
      at System.RuntimeMethodHandle.PerformSecurityCheck(Object obj, RuntimeMethodHandleInternal method, RuntimeType parent, UInt32 invocationFlags)
      at System.RuntimeMethodHandle.PerformSecurityCheck(Object obj, IRuntimeMethodInfo method, RuntimeType parent, UInt32 invocationFlags)
      at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
      at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
      at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture)
      at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, Object[] index)
      at System.Windows.CLRPropertyListener.get_Value()
      at System.Windows.PropertyAccessPathStep.ConnectToPropertyInSource(Boolean isSourceCollectionViewCurrentItem).
      System.Windows.Data Error: Cannot get ‘RootUI’ value (type ‘System.Windows.FrameworkElement’) from ‘Microsoft.LightSwitch.Presentation.Implementation.Screens.PresentationScreenView’ (type ‘Microsoft.LightSwitch.Presentation.Implementation.Screens.PresentationScreenView’). BindingExpression: Path=’RootUI’ DataItem=’Microsoft.LightSwitch.Presentation.Implementation.Screens.PresentationScreenView’ (HashCode=58483472); target element is ‘System.Windows.Controls.ContentPresenter’ (Name=’TheWindow’); target property is ‘Content’ (type ‘System.Object’).. System.MethodAccessException: Attempt by method ‘System.Windows.CLRPropertyListener.get_Value()’ to access method ‘Microsoft.LightSwitch.Presentation.Implementation.Screens.PresentationScreenView.get_RootUI()’ failed.
      at System.RuntimeMethodHandle.PerformSecurityCheck(Object obj, RuntimeMethodHandleInternal method, RuntimeType parent, UInt32 invocationFlags)
      at System.RuntimeMethodHandle.PerformSecurityCheck(Object obj, IRuntimeMethodInfo method, RuntimeType parent, UInt32 invocationFlags)
      at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
      at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
      at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture)
      at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, Object[] index)
      at System.Windows.CLRPropertyListener.get_Value()
      at System.Windows.PropertyAccessPathStep.ConnectToPropertyInSource(Boolean isSourceCollectionViewCurrentItem).

      Thanks,
      MikeH

  3. Hey Jan,

    Looks like my problem is that my Application Type is Web. When I switched it to Desktop everything works fine. Is there a way to get this to work for a Web Application Type?

  4. Hi Jan
    I have the same problem, if the Application type is set to Web, a blank screen is showed.
    is there a solution for web apps?
    Thanks

  5. Pingback: Understanding the decorator pattern. « Jan Van der Haegen's blog

  6. Pingback: CrudQRS, a pragmatic approach to CRUD and CQRS using LightSwitch « Jan Van der Haegen's blog

  7. Great Work Jan !! This has been one of my long standing wishes from LightSwitch to have something like this out of the box.

    Btw, I tried using your code in LightSwitch 2011 and I ran into an exception when trying to get an instance of IServiceProxy (VsExportProviderService.GetExportedValue()).

    >>
    The composition produced a single composition error. The root cause is provided below. Review the CompositionException.Errors property for more detailed information.

    1) Unable to find any implementation of the contract: ‘Microsoft.LightSwitch.Sdk.Proxy.IServiceProxy’
    >>

    According to MSDN it should work with LightSwitch 2011. Do you have any idea what could possibly be wrong?

    Thanks

    • Hey Orion!

      I haven’t tested this with 11 myself, because the XAML of the “MyModalWindow” directly references the Cosmopolitan shell & theme to do the visual rendering… If you would update this XAML, I suppose this could work in LSv1.0 too!
      Weird exception you get, but this MSDN page (http://msdn.microsoft.com/en-us/library/hh290138.aspx#BKMK_CreateExtensionProject) describes on how you could add that DLL if it’s missing in the “Add references
      ” chapter. Perhaps this would do the trick for you :-s
      I have a couple more deadlines this weekend and the week after, but after that I’ll be coding LS for the community again (more blog posts, update on EME, …) I hope to make some time to work with you to get this working in VS 11 too!

      Keep rocking LS!

      Jan

      • Thanks Jan ! I saw that MSDN page earlier and added the reference. Without the dll, it won’t even compile.

        I will look forward to your solution for LS v1.0.

        Thanks a lot.

      • Hi Jan,
        Article is superb, many thanks. Unfortunately I’m stuck at the moment with Lightswitch V1 in VS2010 since some of the extensions I use in my apps have no VS2012 RC update as yet.

        I’ve tried implementing this in VS2010; everything builds and compiles, i get no run-time errors, but my ‘Modal Host’ just displays blank. (OOB App). I’ve checked that the ‘injected’ viewmodel gets instantiated, and it does. I’ve had to blamk out all the xaml in the ‘host’ window that has anything to do with ‘Cosmopolitan theme’ of course since this won’t work in VS2012RC.

        So I guess I need different xaml. It seems that the UI is not binding to the injected viewmodel.
        Can you offer any suggestions?

        Thanks!

        Ian Mac

  8. Pingback: Beth Massi - Sharing the goodness

  9. Pingback: Beth Massi的中文博客

  10. Pingback: Windows Azure and Cloud Computing Posts for 7/10/2012+ - Windows Azure Blog

  11. Hi Jan,

    Sorry if this post is in the wrong section or unrelated.

    PLEASE can you point me to how I can use the DataForm custom control in Lightswitch. All my reading has not helped me.

    Many thanks

  12. Hi Jan
    I have try your solution. Its really very useful one. But unfortunately in my case its not wotking. Everything is correct but when i am trying to save the data from reusable modal window its firing an exception in MyModalWindow.xaml.cs class file within CloseModalWindow method. The exception is InvalidOperationException was unheld by user code.

    Can you please consult me for what i am getting this exception?

    If you provide your email id then it will be more useful for me to send the sample project to you for correction.

    You can also send me direct message through twitter.

    Thanks

  13. Hi!
    Thanks for this great post, it really saved the day for me in my project.

    I’m running Lightswitch 11 and had to do some modifications to the code to get it to run but it’s running fine now.

    My CustomModalHost.xaml looks something like this:

    The screen converter is needed for the validation viewer to work and looks like this:
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
    var screen = value as IScreenView;

    var runningScreen = new RunningScreen(screen, new ScreenValidationViewModel(screen.Screen));
    return runningScreen;
    }

    Another change I did was to set the caller screen as owner of the modal so that it only blocks the current tab in the application.

    I added a line to the constructor of ModalCall:
    ModalHostView.Owner = (Control)CallerView.RootUI;

    And then changed the Show call in ModalHelper to this:
    modalCall.ModalHostView.Show(caller, null);

    Those changes was made with trial-and-error and peeking in JustDecompile, some more documentation about this would be nice…

    • The XAML was mangled, gonna give it a shot by removing the angle-brackets:
      <Grid>
      <Grid.RowDefinitions>
      <RowDefinition Height=”Auto” />
      <RowDefinition Height=”*” />
      </Grid.RowDefinitions>
      <DefaultShell:ValidationViewer Grid.Row=”0″ DataContext=”{Binding Converter={StaticResource ScreenConverter}}”/>
      <ContentPresenter x:Name=”TheWindow” Grid.Row=”1″ Content=”{Binding RootUI}” />
      </Grid>

    • Hey Ramin!
      In the ModalHelper class there’s two methods that close a modal screen. You could add your own even there.
      I’ll include this in an extension soon and include the event-hook :-) If you need some help be sure to let me know! :-)
      Keep rocking LS!

  14. I am getting an error when copying your xaml. Do I need to add a reference? I am using lightswitch 2012 which comes with the cosmoploitan theme. Error is on the line
    “clr-namespace:Microsoft.LightSwitch.Cosmopolitan.Presentation.Controls;assembly=Microsoft.LightSwitch.Cosmopolitan.Client”

    The error is :

    Undefined CLR namespace. The ‘clr-namespace’ URI refers to a namespace ‘Microsoft.LightSwitch.Cosmopolitan.Presentation.Controls’ that could not be found.

    Any help would be appreciated
    Thanks
    Rob

    • Hey Rob,

      also (besides the code sample), the designer won’t work, but it will work during runtime. This is due to the fact that LS only brings the extensions (cosmo) together at runtime :(
      Keep rocking LS!

  15. Jan,
    I read the book you wrote title is “LightSwitch Succinctly” it could help me more easy to join lightswitch camp.
    BTW, Could you the example reusable modal screen because I didn’t know perfectly where could I put the code. Hope your help.

  16. Thanks for this great post Jan.

    I’m trying to use it but I’m getting some issues.

    I’ve defined int he calling sreen a screen data item as an entity, let’s say Article and I want to pass it to the reusable dialog to be edited on it.

    In the dialog I’ve also defined the same Article entity and I’m using the following code:

    partial void ItemSearchArticle_Execute()
    {
    // Write your code here.
    this.Article = (from a in this.DataWorkspace.ApplicationData.Articles
    where a.Brand.Name == this.Brand.Name &&
    a.Code == ItemArticleCode
    select a).FirstOrDefault();
    if (this.Article != null)
    this.PurchaseOrderItems.SelectedItem.Article = this.Article;
    else
    {
    this.Article = new LightSwitchApplication.Article();
    Microsoft.LightSwitch.Threading.Dispatchers.Main.BeginInvoke(() =>
    {
    CreateNewArticleDialog viewModel = CreateNewArticleDialog.CreateInstance();
    viewModel.Article = this.Article;
    ModalHelper.ShowModalWindow(this, viewModel);
    });
    }
    }
    in the Dialog window I have an OK button and I put the following code in the CanExecute method:

    partial void OK_CanExecute(ref bool result)
    {
    // Write your code here.
    result = !this.Article.Details.ValidationResults.HasErrors;
    }

    When I try to run the application in the CanExecute method I got the InvalidOperationException “Impossible to access the object from the current thread”.

    How would you manage a situation like this?

    Moreover, as I have in the dialog modal window the Ok and Cancel button, how can I get notified in the calling screen about wich button has been pressed and execute some code?

    It would be good to have the possibility in the ModalHelper.ShowModalWindow to specify a callback method and passing the modal result to it in order to run some piece of code based on the pressed button.

    Antonio

  17. I get InvalidOperationException “It is not valid to access this object on the current thread.” when I use the modal. It happens on the line
    call.CallerView.EndModal(call.ModalHostView);

  18. here is the revised code:

    public static void CloseModalWindow(ModalCall call, bool closeHostView)
    {

    if (call != null && calls.Remove(call))
    {

    Microsoft.LightSwitch.Threading.Dispatchers.Main.BeginInvoke(() =>
    {
    call.CallerView.EndModal(call.ModalHostView);
    });

    if (closeHostView)

    call.ModalHostView.Dispatcher.BeginInvoke(

    () =>

    call.ModalHostView.Close()

    );

    }

    }

  19. Jan It work’s great but If I do show a window from another modal window it popup as readonly(or something like readonly). Is posible to have multiple levels of modal windows ??
    Thanks for your sharing…..

  20. This is great but it has the same defect as opening a modalwindow defined in a screen, if you press the enter key while a dialog is shown, it closes.
    Is there a way to avoid this behavior?

  21. Here’s one for you, Jan…
    Can you think of some way to return information from the modal window to the main window which called it?
    I was trying to read some of the properties from the CreateInstance modal window. However, it seems like the ShowModalWindow returns immediately, and not when the modal window actually closes, so I’m only managing to get the initial value of the property, not what it is after it’s been edited on the modal window.

  22. Hi Jan, Thank You for the post. Exactly what I was look for. I have question. Can I save the data to the ‘ApplicationData’ object in the modal window. I see your comment ‘Run your code here on the server’.

    I am trying to set some properties on ‘Ticket’ entity and save changes. i get the ‘Cannot access this object in the current thread’ error?

    Any suggestions in the regard?

    Thanks for sharing your awesome work.

  23. I have attempted to create the class, I am getting an error in the

    public static void CloseModalWindow(IScreenObject modalWindowToClose)
    {

    CloseModalWindow(

    Calls

    c.ModalChildViewModel == modalWindowToClose).FirstOrDefault()

    , true);

    }

    I am still new to all this , any help would be greatly appreciated, also If you have a better writeup to follow on how to implement this , would also be great

    thanks

    Lightswitch Noob
    David

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s