Integrating RadDialogs (Confirm, Alert, Prompt) with PRISM's InteractionRequest using MVVM

Thread is closed for posting
17 posts, 0 answers
  1. Marco
    Marco avatar
    13 posts
    Member since:
    Aug 2012

    Posted 19 Aug 2014 Link to this post

    Requirements

    Telerik Product and Version

    all, tested with Q2 2014

    Supported Browsers and Platforms

    .Net 4
               

    Components/Widgets used (JS frameworks, etc.)

    PRISM v5

    PROJECT DESCRIPTION 
    In order to separate the view from the viewmodel, dialogs should not be opened in the viewmodel, although this scenario is often needed. Our original issue was to position the dialog on top of the calling window (which is not the main window in our RadDocking scenario). PRISM is providing InteractionRequest objects, in order to delegate the creation of dialogs from the viewmodel to the view, but the given implementation is using the WPF window. (see http://msdn.microsoft.com/en-us/library/gg405494#sec12)

    Based on this implementation, we created a version using RadWindow:

    namespace Infrastructure
    {
        using System;
        using System.Windows;
        using System.Windows.Interactivity;
     
        using Microsoft.Practices.Prism.Interactivity.InteractionRequest;
     
        using Telerik.Windows.Controls;
     
        public interface IRadDialog : INotification
        {
            bool? DialogResult { get; set; }
            DialogParameters DialogParameters { get; set; }
            string PromptResult { get; set; }
        }
     
        internal interface IRadConfirmation : IRadDialog
        {
        }
     
        internal interface IRadAlert : IRadDialog
        {
        }
     
        internal interface IRadPrompt : IRadDialog
        {
        }
     
        public abstract class RadDialog : Notification
        {
            public bool? DialogResult { get; set; }
            public DialogParameters DialogParameters { get; set; }
            public string PromptResult { get; set; }
        }
     
        public class RadConfirmation : RadDialog, IRadConfirmation
        {
        }
     
        public class RadAlert : RadDialog, IRadAlert
        {
        }
     
        public class RadPrompt : RadDialog, IRadPrompt
        {
        }
     
     
        /// <summary>
        /// Shows a popup window in response to an <see cref="Microsoft.Practices.Prism.Interactivity.InteractionRequest"/> being raised.
        /// </summary>
        public class RadDialogPopupWindowAction : TriggerAction<FrameworkElement>
        {
            /// <summary>
            /// Displays the child window and collects results for <see cref="IInteractionRequest"/>.
            /// </summary>
            /// <param name="parameter">The parameter to the action. If the action does not require a parameter, the parameter may be set to a null reference.</param>
            protected override void Invoke(object parameter)
            {
                var args = parameter as InteractionRequestedEventArgs;
                if (args == null)
                {
                    return;
                }
     
                var dialog = args.Context as IRadDialog;
     
                var callback = args.Callback;
                EventHandler<WindowClosedEventArgs> handler = null;
                handler =
                    (o, e) =>
                        {
                            dialog.DialogParameters.Closed -= handler;
                            dialog.DialogResult = e.DialogResult;
                            dialog.PromptResult = e.PromptResult;
                        if (callback != null) callback();
                    };
     
                dialog.DialogParameters.Closed += handler;
     
                dialog.DialogParameters.Owner = Window.GetWindow(this.AssociatedObject);
     
                if (args.Context is IRadPrompt)
                {
                    RadWindow.Prompt(dialog.DialogParameters);
                }
                else if (args.Context is IRadAlert)
                {
                    RadWindow.Alert(dialog.DialogParameters);
                }
                else if (args.Context is IRadConfirmation)
                {
                    RadWindow.Confirm(dialog.DialogParameters);
                }
            }
        }
    }

    The following line from above, was the solution to our issue to position the dialog on top of the calling window:

    dialog.DialogParameters.Owner = Window.GetWindow(this.AssociatedObject);


    In the calling viewmodel, you have to set the following property and instantiate it in the constructor:

    public InteractionRequest<IRadDialog> ConfirmationRequest { get; private set; }
     
    public Class1(){
        ConfirmationRequest = new InteractionRequest<IRadDialog>();
    }

    To show the dialog box, you can use following code snippet inside the viewmodel:

    this.ConfirmationRequest.Raise(
            new RadConfirmation
                {
                    DialogParameters = param // Telerik DialogParameters
                },
            confirmation =>
                {
                    Console.WriteLine(confirmation.DialogResult + confirmation.PromptResult);
                });

    To show the different types of dialogs, you simply have to instantiate the corresponding classes (RadConfirmation, RadAlert, RadPrompt)

    The view has to know about the interaction request, which could be done completely in XAML:

    <UserControl x:Class="ViewModule.View"
                 [...]            
                 xmlns:interactivity="http://www.codeplex.com/prism"
                 xmlns:infrastructure="clr-namespace:Infrastructure;assembly=Infrastructure">
     
    <i:Interaction.Triggers>
            <interactivity:InteractionRequestTrigger SourceObject="{Binding ConfirmationRequest, Mode=OneWay}">
                <infrastructure:RadDialogPopupWindowAction/>                  
            </interactivity:InteractionRequestTrigger>
        </i:Interaction.Triggers>

    That's all you need to use RadDialogs the MVVM Style with PRISM!

  2. Yana
    Admin
    Yana avatar
    5044 posts

    Posted 21 Aug 2014 Link to this post

    Hi Marco,

    Thank you for sharing the code. I have updated your Telerik points for your involvement.

    Regards,
    Yana
    Telerik
     
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
     
  3. Erik
    Erik avatar
    52 posts
    Member since:
    Jan 2011

    Posted 07 Oct 2014 Link to this post

    This is awesome stuff.  Helped me in a project to add some polish and shine to it.  Thanks for posting.
  4. Jonathan
    Jonathan avatar
    14 posts
    Member since:
    Jan 2012

    Posted 22 Jan 2015 Link to this post

    Thumbs up to Marco for the share. May I ask one thing, can you also provide an extension to WindowContent so that it accepts custom views?

    Cheers
  5. Marco
    Marco avatar
    13 posts
    Member since:
    Aug 2012

    Posted 27 Jan 2015 Link to this post

    Hi Jonathan,

    I extended the class with a new DependencyProperty "ContentOverride" which you can set in XAML. You can override any other property of DialogParameters accordingly.

    For a showcase see the attached project.

    Kind Regards,
    Marco
  6. Jonathan
    Jonathan avatar
    14 posts
    Member since:
    Jan 2012

    Posted 28 Jan 2015 in reply to Marco Link to this post

    Hi Marco,

    I'm not sure if I'm doing it correctly. It doesn't seem to work on my end. So far, this is what I have:

    In my Infrastructure project, I've created a new Notification inheriting from RadConfirmation.

    In my Main project, I have this in my View:

    <prism:InteractionRequestTrigger SourceObject="{Binding QuantityChangeRequest, Mode=OneWay}">
        <infrastructure:RadDialogPopupWindowAction>
            <infrastructure:RadDialogPopupWindowAction.ContentOverride>
                <views:QuantityChangeView />
            </infrastructure:RadDialogPopupWindowAction.ContentOverride>
        </infrastructure:RadDialogPopupWindowAction>
    </prism:InteractionRequestTrigger>

    And in my ViewModel, I have this:

    private void ChangePosItemQuantity()
    {
        if (SelectedPosItem == null)
            SelectedPosItem = posItems.OrderByDescending(x => x.number).First();
     
        var notification = new ItemQuantityChangeNotification();
        notification.DialogParameters = new Telerik.Windows.Controls.DialogParameters();
        notification.DialogParameters.Header = "Quantity";
     
        this.QuantityChangeRequest.Raise(notification, returned =>
            {
                if (returned != null && returned.Confirmed)
                {
                    SelectedPosItem.quantity = returned.Quantity;
                    SelectedPosItem.CalculateSubtotal();
     
                    var selectedItem = SelectedPosItem;
                    OnPropertyChanged("PosItems");
                    SelectedPosItem = selectedItem;
                }
            });
    }

    And finally, I have a RadWindow as my QuantityView.

    However, I end up getting a RadWindow prompt without any content. I'm rather new to WPF, so your help is very much appreciated.
  7. Marco
    Marco avatar
    13 posts
    Member since:
    Aug 2012

    Posted 28 Jan 2015 in reply to Jonathan Link to this post

    Hi Jonathan,

    with this:

    <infrastructure:RadDialogPopupWindowAction.ContentOverride>
       <views:QuantityChangeView />
    </infrastructure:RadDialogPopupWindowAction.ContentOverride>

    you try to add a RadWindow inside the RadWindow of the Notification which is not possible.

    I just added the visual items directly:

    <infrastructure:RadDialogPopupWindowAction.ContentOverride>
       <TabControl>
          <TabItem Header="test 1">test</TabItem>
          <TabItem Header="test 2">Test2</TabItem>
       </TabControl>
    </infrastructure:RadDialogPopupWindowAction.ContentOverride>

    However my solution just replaces the Content property of the DialogParameters.

    Note: If you need to access items of the ContentOverride in your viewmodel, this solution is not sufficient.

    If you can tell me in more detail what you are trying to achieve, maybe I can prepare a proper example for you.  




  8. Jonathan
    Jonathan avatar
    14 posts
    Member since:
    Jan 2012

    Posted 28 Jan 2015 in reply to Marco Link to this post

    Hi Marco,

    Thanks for your quick response. It's fairly simple, I'm trying to do a Popup window (as you know, WPF popup has a 75% size limitation) using Telerik's RadWindow. It has its own ViewModel and logic. As its name suggests, this View would have some UI that would allow users to change Quantity, once done, closes itself and then return the updated quantity to the host (the main view). I followed Prism 5.0 Interactivity example and I managed to get it working, only the size constraint is a matter, hence my intention to use RadWindow.
  9. Marco
    Marco avatar
    13 posts
    Member since:
    Aug 2012

    Posted 28 Jan 2015 in reply to Jonathan Link to this post

    Hi Jonathan,

    sorry but i think, this is way behind the goal of the example. Custom windows with own viewmodels are not in the scope. As a start you may look at the source code of the PRISM PopupWindowAction to integrate the RadWindow the way you need it.

    Sorry for not helping you further.

    Kind Regards,

    Marco
  10. Jonathan
    Jonathan avatar
    14 posts
    Member since:
    Jan 2012

    Posted 28 Jan 2015 in reply to Marco Link to this post

    No prob. Thanks mate. Your help is very much appreciated. Cheers
  11. Marco
    Marco avatar
    13 posts
    Member since:
    Aug 2012

    Posted 29 Jan 2015 in reply to Jonathan Link to this post

    Hi Jonathan,

    i could spare some time and looked into PRISM's PopupWindowAction. Actually the implementation isn't that complicated and so, i changed the used WPF Window instance to a RadWindow. The sample project is attached.

    I've created a CustomDialogPopupWindowAction, where you HAVE TO set the property WindowContent to your VIEW (Not window!), otherwise an exception is thrown. 

    As long as you are following the PRISM Interactivity Guide (https://msdn.microsoft.com/en-us/library/ff921081(v=pandp.40).aspx) section "Complex Custom Popup Windows" everything should be fine.

    If you need further help, please ask.

    Kind Regards,

    Marco


  12. Jonathan
    Jonathan avatar
    14 posts
    Member since:
    Jan 2012

    Posted 29 Jan 2015 in reply to Marco Link to this post

    Thanks Marco. It does indeed work. Now I just have to extend it further to show fullscreen and it's done. Cheers.
  13. Ram
    Ram avatar
    20 posts
    Member since:
    Nov 2014

    Posted 02 Feb 2015 in reply to Marco Link to this post

    Thanks Marco for your sample solution.

    How can I also get the default Confirmation and Notification popups to work using your CustomDialogPopupWindowAction class?

    The below code no longer works and I get an error saying "WindowContent has to be set" -

    <prism:InteractionRequestTrigger SourceObject="{Binding NotificationRequest, Mode=OneWay}">
    <infrastructure:CustomDialogPopupWindowAction IsModal="True" CenterOverAssociatedObject="True"/>
    </prism:InteractionRequestTrigger>

    Thanks
  14. Jonathan
    Jonathan avatar
    14 posts
    Member since:
    Jan 2012

    Posted 02 Feb 2015 in reply to Ram Link to this post

    Ram said:Thanks Marco for your sample solution.

    How can I also get the default Confirmation and Notification popups to work using your CustomDialogPopupWindowAction class?

    The below code no longer works and I get an error saying "WindowContent has to be set" -

    <prism:InteractionRequestTrigger SourceObject="{Binding NotificationRequest, Mode=OneWay}">
    <infrastructure:CustomDialogPopupWindowAction IsModal="True" CenterOverAssociatedObject="True"/>
    </prism:InteractionRequestTrigger>

    Thanks


    Ram, refer to Marco's last post before mine.
  15. Jonathan
    Jonathan avatar
    14 posts
    Member since:
    Jan 2012

    Posted 02 Feb 2015 Link to this post

    Looks like I can't edit my last post. Ram, kindly note this, what Marco has shown in his last post enables you to drop a custom view into your RadWindow. Hence, WindowContent must ALWAYS be set in such a case. If all you're looking for is a simply RadWindow dialog, refer to his first post where he inherits from INotification.
  16. Kalin
    Admin
    Kalin avatar
    1364 posts

    Posted 05 Feb 2015 Link to this post

    Hi Marco,

    We would like to thank you for sharing additional helpful information and samples. We have updated your Telerik points for your involvement.

    Regards,
    Kalin
    Telerik
     
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
     
  17. Ram
    Ram avatar
    20 posts
    Member since:
    Nov 2014

    Posted 04 Mar 2015 in reply to Kalin Link to this post

     Hello Marco,

    Another question - the CenterOverAssociatedObject="True" does not position the popup window in the middle of the parent window. How can be fixed? It is always positioned at the top left corner.

    <i:Interaction.Triggers>
    <interactionRequest:InteractionRequestTrigger SourceObject="{Binding ConfirmationRequest, Mode=OneWay}">
    <infrastructure:CustomDialogPopupWindowAction CenterOverAssociatedObject="True">
    <infrastructure:CustomDialogPopupWindowAction.WindowContent>
    <mainWindowModule:QuantityCustomDialog/>
    </infrastructure:CustomDialogPopupWindowAction.WindowContent>
    </infrastructure:CustomDialogPopupWindowAction>
    </interactionRequest:InteractionRequestTrigger>
    </i:Interaction.Triggers>

    Thanks
Back to Top

This Code Library is part of the product documentation and subject to the respective product license agreement.