Creating Popup Dialog using Jounce Region.

It is little trickier to create a Silverlight pop up dialog box using Jounce. Jounce creates view and associate the viewmodel to it for user controls while pop up dialog boxes are derived off of ChildWindow. So you can not just navigate/region to the control. Even if you would ‘new’ up a dialog, you will lose the View Model associated with it from Jounce Frame work, since you are newing the view. If you would new the view, then you need to revert back to old school view mode injection through code behind, if you would take that approach then you are not really using Jounce to create a good MVVM code. To make it short, it is trickier to use Jounce Framework to show your Child Window (in our case we use C1Window – Component One Child Window). But as you can imagine that since I am writing the block, it is possible and surprisingly easy.

One of my colleague found a hack by goggling. Once I get the link, I will put the link up here so that you get the actual implementation by the original author. We modified a little bit to handle our situation,  Here is the solution;

1. Create a normal User Control page and wrap the content in a Canvas, it is important you have canvas, if you use Grid then the user will not able to move the pop up window around. You can only maximize, minimize and close. If you would use Canvas, then you can do all the things you do with Grid but also move the pop up window around. By default make the canvas collapsed.

2. Create a C1Window, name the control.

3. Inside the C1Window, create a ‘ContentControl’ and give a region name. Here is where we are going to place our view.

4. When user want to activate the dialog, make the Canvas visible. Also navigate to the view, which will be exported to region defined in the Content Control.

5. When all the actions are done, close the dialog, navigate back to the calling page, make the Canvas visibility to Collapsed.

I wrote a simple solution to show how it works. Here is the main page XAML, which has a button, when clicked it is suppose to show the pop up dialog.

    <Grid x:Name="LayoutRoot" Background="White"
          d:DataContext="{d:DesignInstance sampleData:DesignMainViewModel, IsDesignTimeCreatable=True}">
        <Grid.Resources>
            <local:Converters x:Key="myConverter"/>
        </Grid.Resources>
        <StackPanel>
        <Button Content="Click me" Command="{Binding ClickMe}"/>
        <Canvas Name="hiddencanvas" Visibility="Collapsed">            
                <c1:C1Window Header="Title" Height="200" Width="200">
                    <i:Interaction.Triggers>
                        <i:EventTrigger EventName="Closing">
                            <i:InvokeCommandAction Command="{Binding ClosingCommand}" CommandParameter="{Binding Converter={StaticResource myConverter}}"/>
                        </i:EventTrigger>
                    </i:Interaction.Triggers>
                    <ContentControl  Region:ExportAsRegion.RegionName="ShowMeRegion"/>
                </c1:C1Window>
            </Canvas>
        </StackPanel>
    </Grid>

 

The button which initiate the pop up dialog bound to the command ClickMe in the ViewModel. For time being ignore the event trigger.

*** Edit on the above code **

Replaced the trigger with behavior as follows

<i:Interaction.Behaviors>
   <local:CloseBehavior/>
</i:Interaction.Behaviors>  

local class which implements close behavior as follow
public class CloseBehavior : Behavior<C1Window>
    {
        public CloseBehavior()
            : base()
        {
        }

        protected override void OnAttached()
        {
            base.OnAttached();
            AssociatedObject.Closing += new CancelEventHandler(AssociatedObject_Closing);
        }

        void AssociatedObject_Closing(object sender, CancelEventArgs e)
        {
            e.Cancel = true;
            Canvas c = AssociatedObject.Parent as Canvas;
            c.Visibility = Visibility.Collapsed;
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();
            AssociatedObject.Closing -= new CancelEventHandler(AssociatedObject_Closing); 
        }

    }

*** End Edit ****

 
[ExportAsViewModel("MainViewModel")]
    public class MainViewModel : BaseViewModel
    {
        public IActionCommand<string> ClickMe { get; set; }
        public IActionCommand<CancelEventArgs> ClosingCommand { get; set; }

        public MainViewModel()
        {
            ClickMe = new ActionCommand<string>(
                view =>
                {
                    EventAggregator.Publish("ShowCanvas");
                    EventAggregator.Publish("ShowMe".AsViewNavigationArgs());
                }
                );

            ClosingCommand = new ActionCommand<CancelEventArgs>(
                view =>
                {
                    view.Cancel = true;
                }
                );
        }

    }

 

If you notice the ClickMe method implementation, it fires two events. First one is called ShowCanvas, which will be intercepted at the code behind to make the canvas visible. The second event is to stage the view you want to show in the view model. Lets look at the code behind and see how it makes the canvas visible.

[ExportAsView("MainPage", IsShell = true)]
    public partial class MainPage : UserControl, IPartImportsSatisfiedNotification, IEventSink<string>
    {
        [Import]
        public IEventAggregator EventAggregator { get; set; }

        public MainPage()
        {
            InitializeComponent();
        }

        [Export]
        public ViewModelRoute Binding
        {
            get { return ViewModelRoute.Create("MainViewModel", "MainPage"); }
        }

        #region IPartImportsSatisfiedNotification Members

        public void OnImportsSatisfied()
        {
            EventAggregator.Subscribe<string>(this);
        }

        #endregion

        #region IEventSink<string> Members

        public void HandleEvent(string publishedEvent)
        {
            if (publishedEvent.Equals("ShowCanvas"))
                hiddencanvas.Visibility = System.Windows.Visibility.Visible;
        }

        #endregion

    }

If you look at the HandleEvent method at the end of the code, you will see, we are checking the incoming message to see if it is ‘ShowCanvas’ then make the canvas visible.

Now lets go back to the second call made from the view model to load the ‘ShowMe’ page. it is important that, here you use User Control, so that Jounce does the wiring for you. The ShowMe.XAMl look like the following, nothing fancy

    <Grid x:Name="LayoutRoot" Background="White">
        <TextBlock Text="Hello from Popup Window" FontSize="16"/>
    </Grid>

In the code behind, as you would do to any user control which needed to be hosted in a region, export it to the region when called.

[ExportAsView("ShowMe")]
[ExportViewToRegion("ShowMe", "ShowMeRegion")]
public partial class ShowMe : UserControl
{
    public ShowMe()
    {
        InitializeComponent();
    }
}

 

That’s about it. I added a small twist to the code, by listening to Closing event of the pop up window using Event Trigger. Just an experiment that’s all. You can very well add the Closing event in the code behind and all will be good as well.

Advertisements

6 thoughts on “Creating Popup Dialog using Jounce Region.

    • I did not attempt it but, using Canvas inside another canvas with region name, you could create multiple pop-ups one top of another. If and when I try this, I will post what I find in here.

  1. Hi,
    It is a nice post but I need your help on when closing the popup, how do you deactivate the view in the childwindow’s content.

    Thanks
    Imthi

    • On closing event, we basically collapse the pop up panel since it is a panel inside the same screen. Like the following
      Canvas c = AssociatedObject.Parent as Canvas;
      c.Visibility = Visibility.Collapsed;

      • Hi Unni,

        Thanks for the reply. The viewmodel is still on previous state when I try to open the popup again. All I am looking for a stateless popup. The Visibility.Collapsed just hides the popup but the view model is not cleared. Hope I have made my query clearer.

        Thanks
        Imthi

      • I take it, you are using the same view model for the view and also the popup. Based on the pop up request, you are serving the view and show it on the screen. At this time, it is using the same view model. When you close the popup, like you said, only changing the visibility to false, you are still in the view model. Couple of things I think you can do, first one is Jeremy is working on the new framework where popup dialogue is going to be first class citizen then you will have view/viewmodel associated to popup itself. You can take that and try it out. Second option I can think of is to when you launch the popup, you could create a class which have information for the popup and populate the view. On close you destroy the instance or clear the values of the instance so that when you come back when it is trying to bind the values they are all reset on the last close so that it will be empty. If this not clear, please send me a mail to ksunairatyahoo.com

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