Ticket Q427991
Visible to All Users
Duplicate

We have closed this ticket because another page addresses its subject:

Show complex dialogs in XAF ASP.NET applications (similar to the MessageBox in Windows Forms)

Web - implement windows-like MessageBox

created 13 years ago

Hi!

I know, there are tons of ticket with similar requests and yet - here is another one.

XAF is an application framework being most suitable for building business solutions. Business solutions requires A LOT of confirmation/information/warning/error dialogs. A lot. Did I say a lot? Good.

I don't think anyone should spent more than an hour (like I just did) trying to find proper solution to display dialogs whether error/information or confirmation ones and after the search, feeling numb & dumb, having in hands few hack solutions using popup actions or popup controls (which then one needs to find out how to customize them from ViewController - which I still need to do and waste another hour of time - for a message box).

So, let me summarize this.
DevExpress - you need to - and let me repeat that - YOU REALLY NEED TO build static MessageBox class because:
 - I want to type MessageBox.Show("Hello user, I love using this simple dialogs so I can inform you");
- I want to type MessageBox.Show("User, if you do this, you die!", MessageBoxButtons.Ok, MessageBoxIcon.Error);
- I want to type MessageBox.Show("Saving data", "Are you sure you want to save this?", MessageBoxButtons.YesNo, MessageBoxIcon.Question);

Because I don't want to:
- spend hours to figure out ways how to actually display message
- feeling numb&dumb when I actually do find out how to do it
- doing hacks with popup control and figuring out how to customize it from view controller so that I don't have to create 100 popup controls each with different information in it

Dennis wrote: I want to close this ticket with a solution that was successfully used by many of our users through these years. ( S19008)
Dennis, it was successfully used because they had no other choice and believe me - they would all be much happier if they would have found MessageBox.Show and not to waste time and resources on bluntly simple task like this.
XAF can be (and it really is) a real time saver, but then it can also be such a time-killer that I simply can't believe why such tasks haven't been implemented in a framework with most tendencies turned to building business applications.

I will solve my current problem with popup control (I can't use UserFriendlyException, I will create another ticket for that one), not because I want, but because I have no other choice.
So, PLEASE, do implement nice and elegant solution for this.

Thanks,

Mario

Show previous comments (2)
WC WC
Warren Connors 4 10 years ago

    Mario - notice Michael's latest comment (2/13/2015) - still working on trying to get the web version to work properly :(

    WC WC
    Warren Connors 4 10 years ago

      Hey Mario, I gave up on trying to come up with a platform-agnostic confirmation message popup. (See latest entries from me) - But I converted everything to an informational-message only popup (which is platform-agnostic) because I think that still might be very useful by itself. I am going to continue on a different tack to try to implement a web app specific confirmation popup referencing some of Dennis' suggestions. C'est la vie :)

        Thanks for the effort.

        Answers

        created 13 years ago (modified 13 years ago)

        Hi Mario,
        Thank you for your feedback. I am afraid we cannot provide a built-in static method similar to MessageBox.Show in Web, because of the Web technology nature. According to the ASP.NET page life cycle, every web page update initiated by a client is a separate process. It is impossible to continue the execution of your code from the line after the MessageBox.Show method call, because the code that shows a dialog should finish with a response sent to the client browser. When the user closes the dialog, the client browser sends another request to your web application, and the application processes it in the standard manner by re-creating web controls, raising certain events etc. So, you can process the dialog result only by handling DialogController events raised by corresponding dialog actions.

          Show previous comments (17)
          WC WC
          Warren Connors 4 10 years ago

            And finally, if my previous 2 posts are correct, then in our company's system, I will probably keep the main module MessageBox class that we have been working with here, but will change the name of the MessageBox class to InfoMessageBox to call out the fact that in web apps it can only be used reliably to show informational-type messages, not for confirmation messages (as well as putting some comments into the class pointing that out). And will only use it that way in either win or web apps for consistency (because it is in fact pretty useful for informational messages).

            WC WC
            Warren Connors 4 10 years ago

              So… after all that, what we have arrived at now is:  I refactored everything to have an InfoMessageBox class that only displays an informational message (with only one button, the OK button). It is in the main module and seems to work pretty well in both win and web apps for INFORMATIONAL messages only, NOT confirmation messages. I will continue to work on a separate implementation (possibly the AspxPopUp methodology) to get a popup confirmation message for XAF web apps.
              Attached is a full VS2013 solution with the informational-message-only popup message implementation.
              Following are the most important classes for others to utilize (note that if you are going to put these classes in an XAF solution, you must include the State Machine module in the solution for it to work; also notice I placed the InfoMessageBox class in its own folder, "Utility"):
              ==========
              // Code for this taken from DevExpress KB, article Q427991 and modified.
              using DevExpress.Data.Filtering;
              using DevExpress.ExpressApp;
              using DevExpress.ExpressApp.Actions;
              using DevExpress.ExpressApp.Editors;
              using DevExpress.ExpressApp.Layout;
              using DevExpress.ExpressApp.Model.NodeGenerators;
              using DevExpress.ExpressApp.SystemModule;
              using DevExpress.ExpressApp.Templates;
              using DevExpress.ExpressApp.Utils;
              using DevExpress.Persistent.Base;
              using DevExpress.Persistent.Validation;
              using DevExpress.Xpo;
              using System;
              using System.Collections.Generic;
              using System.Linq;
              using System.Text;
              //using XAFStateMachineDemo.Module.BusinessObjects;
              namespace XAFStateMachineDemo.Module.Utility
              {
                 // This class can be located in the XAF main module, and will display
                 // informational-only popup messages in a platform-agnostic way, i.e., in both
                 // XAF-generated win apps and XAF-generated web apps.
                 // Note that this class CANNOT be used reliably to display confirmation-type messages,
                 // as opposed to informational-only messages. Not in a platform-agnostic way; it IS
                 // possible to make confirmation messages work with this class (if the Cancel button
                 // is not removed) within the XAF-generated win app, but NOT within the XAF-generated
                 // web app.
                 // For confirmation messages (at least as of v14.2) one should just use the DevExpress
                 // XtraMessageBox within XAF-generated win apps (in the win app module/UI), and implement
                 // your own solution for a confirmation message (confirmation meaning that you are able
                 // to cancel the applicable, pending operation) within the web app module/UI.
                 [NonPersistent]
                 public class InfoMessageBox
                 {
                     private string message;
                     public string Message { get { return message; } }
                     private InfoMessageBox(string message)
                     {
                         this.message = message;
                     }
                     public static void Show(XafApplication app, ShowViewParameters svp, string message, Action okMethod)
                     {
                         IObjectSpace os = ObjectSpaceInMemory.CreateNew();
                         InfoMessageBox obj = new InfoMessageBox(message);
                         svp.CreatedView = app.CreateDetailView(os, obj);
                         DialogController dc = app.CreateController<DialogController>();
                         SimpleAction cancelAction = (SimpleAction)dc.Actions["DialogCancel"];
                         cancelAction.Active.SetItemValue("Active", false);  // Hide the cancel button or it will display by default.
                         // Note that by passing in a System.Action delegate for the OK method, it is
                         // technically possible for invoking classes to execute just about any arbitrary
                         // code via the OK button event handler. However, that should be done with
                         // extreme caution. One could even say that doing so violates the general purpose of
                         // this class, as evidenced by even its name, to display INFORMATIONAL type messages.
                         // So, one might choose to modify this class such that an Action delegate is not
                         // passed in, thus completely restricting this from happening; in this example, the
                         // class has the Action input parameter so that each organization can make that
                         // decision. And, perhaps there are some specific, limited use cases for executing
                         // some arbitrary code along with the displaying of the informational message - even
                         // something as simple as logging that an informational message was displayed and what
                         // was in the message, perhaps. If so, this code illustrates how one might do that).
                         dc.Accepting += new EventHandler<DialogControllerAcceptingEventArgs>(delegate
                         {
                             if (okMethod != null) okMethod();
                         });
                         svp.Controllers.Add(dc);
                         svp.Context = TemplateContext.PopupWindow;
                         svp.TargetWindow = TargetWindow.NewModalWindow;
                         svp.NewWindowTarget = NewWindowTarget.Separate;
                     }
                     public static void Show(XafApplication app, string message, Action okMethod)
                     {
                         ShowViewParameters svp = new ShowViewParameters();
                         Show(app, svp, message, okMethod);
                         app.ShowViewStrategy.ShowView(svp, new ShowViewSource(null, null));
                     }
                 }
              }
              ==========
              using DevExpress.Data.Filtering;
              using DevExpress.ExpressApp;
              using DevExpress.ExpressApp.DC;
              using DevExpress.ExpressApp.Model;
              using DevExpress.Persistent.Base;
              using DevExpress.Persistent.BaseImpl;
              using DevExpress.Persistent.Validation;
              using DevExpress.Xpo;
              using System;
              using System.Collections.Generic;
              using System.ComponentModel;
              using System.Linq;
              using System.Text;
              namespace XAFStateMachineDemo.Module.BusinessObjects
              {
                 [DefaultClassOptions]
                 [ImageName("BO_List")]
                 public class InfoMessageBoxLog : BaseObject
                 {
                     public InfoMessageBoxLog(Session session)
                         : base(session)
                     {
                     }
                     public override void AfterConstruction()
                     {
                         base.AfterConstruction();
                         CreateDate = DateTime.Now;
                     }
                     // Fields…
                     private string _Action;
                     private string _MessageInfo;
                     private DateTime _CreateDate;

              [Size(SizeAttribute.DefaultStringMappingFieldSize)]
                     public string Action
                     {
                      get
                      {
                      return _Action;
                      }
                      set
                      {
                       SetPropertyValue("Name", ref _Action, value);
                      }
                     }
                     [Size(SizeAttribute.DefaultStringMappingFieldSize)]
                     public string MessageInfo
                     {
                      get
                      {
                      return _MessageInfo;
                      }
                      set
                      {
                       SetPropertyValue("Description", ref _MessageInfo, value);
                      }
                     }
                     public DateTime CreateDate
                     {
                      get
                      {
                      return _CreateDate;
                      }
                      set
                      {
                       SetPropertyValue("CreateDate", ref _CreateDate, value);
                      }
                     }
                 }
              }
              ==========
              // Example taken from DevExpress KB, article Q427991.
              using DevExpress.Data.Filtering;
              using DevExpress.ExpressApp;
              using DevExpress.ExpressApp.Actions;
              using DevExpress.ExpressApp.Editors;
              using DevExpress.ExpressApp.Layout;
              using DevExpress.ExpressApp.Model.NodeGenerators;
              using DevExpress.ExpressApp.SystemModule;
              using DevExpress.ExpressApp.Templates;
              using DevExpress.ExpressApp.Utils;
              using DevExpress.Persistent.Base;
              using DevExpress.Persistent.Validation;
              using DevExpress.Xpo;
              using System;
              using System.Collections.Generic;
              using System.Linq;
              using System.Text;
              using XAFStateMachineDemo.Module.BusinessObjects;
              using XAFStateMachineDemo.Module.Utility;
              namespace XAFStateMachineDemo.Module.Controllers
              {
                 public partial class InfoMessageBoxTestController : ViewController
                 {
                     public InfoMessageBoxTestController()
                     {
                         InitializeComponent();
                         SimpleAction action = new SimpleAction(this, "TestInfoMessageBox", PredefinedCategory.View);
                         action.Execute += new SimpleActionExecuteEventHandler(action_Execute);
                     }
                     void action_Execute(object sender, SimpleActionExecuteEventArgs e)
                     {
                         string popupMessage = "This is a sample informational message.";
                         InfoMessageBox.Show(Application, popupMessage,
                             new Action(delegate
                                                 {
                                                     InfoMessageBoxLog obj = ObjectSpace.CreateObject<InfoMessageBoxLog>();
                                                     obj.Action = string.Format("InfoMessageBox invoked {0:G}", DateTime.Now);
                                                     obj.MessageInfo = "Message displayed: " + popupMessage;
                                                     ObjectSpace.CommitChanges();
                                                     ObjectSpace.Refresh();
                                                 }));
                     }
                 }
              }
              ==========
              using System;
              using System.Collections.Generic;
              using System.Linq;
              using System.Text;
              using System.Threading.Tasks;
              namespace XAFStateMachineDemo.Module.BusinessObjects
              {
                 public enum PurchaseRequestStatusEnum { Draft, InProgress, Paused, Canceled, Approved }
              }
              ==========
              using DevExpress.Data.Filtering;
              using DevExpress.ExpressApp;
              using DevExpress.ExpressApp.DC;
              using DevExpress.ExpressApp.Model;
              using DevExpress.ExpressApp.StateMachine;
              using DevExpress.ExpressApp.Xpo;
              using DevExpress.Persistent.Base;
              using DevExpress.Persistent.BaseImpl;
              using DevExpress.Persistent.Validation;
              using DevExpress.Xpo;
              using System;
              using System.Collections.Generic;
              using System.ComponentModel;
              using System.Linq;
              using System.Text;
              namespace XAFStateMachineDemo.Module.BusinessObjects
              {
                 [DefaultClassOptions, ImageName("BO_Task")]
                 [System.ComponentModel.DefaultProperty("Description")]
                 public class PurchaseRequest : BaseObject, IStateMachineProvider
                 {
                     public PurchaseRequest(Session session) : base(session)
                     {
                     }
                     [RuleRequiredField("RuleRequiredField for PurchaseRequest.Description", DefaultContexts.Save, "A Description must be specified")]
                     public string Description
                     {
                         get { return GetPropertyValue<string>("Description"); }
                         set { SetPropertyValue<string>("Description", value); }
                     }
                     [RuleRequiredField("RuleRequiredField for PurchaseRequest.CreateDate", DefaultContexts.Save, "A CreateDate must be specified")]
                     public DateTime CreateDate
                     {
                         get { return GetPropertyValue<DateTime>("CreateDate"); }
                         set { SetPropertyValue<DateTime>("CreateDate", value); }
                     }
                     public decimal TotalAmount
                     {
                         get { return GetPropertyValue<decimal>("TotalAmount"); }
                         set { SetPropertyValue<decimal>("TotalAmount", value); }
                     }
                     public PurchaseRequestStatusEnum PurchaseRequestStatus
                     {
                         get { return GetPropertyValue<PurchaseRequestStatusEnum>("PurchaseRequestStatus"); }
                         set { SetPropertyValue<PurchaseRequestStatusEnum>("PurchaseRequestStatus", value); }
                     }
                     [Size(4096)]
                     public string Notes
                     {
                         get { return GetPropertyValue<string>("Notes"); }
                         set { SetPropertyValue<string>("Notes", value); }
                     }
                     // IStateMachineProvider implementation begin.
                     public IList<IStateMachine> GetStateMachines()
                     {
                         List<IStateMachine> result = new List<IStateMachine>();
                         result.Add(new PurchaseRequestStatusStateMachine(XPObjectSpace.FindObjectSpaceByObject(this)));
                         return result;
                     }
                     // IStateMachineProvider implementation end.
                 }
              }
              ==========
              using DevExpress.ExpressApp;
              using DevExpress.ExpressApp.Editors;
              using DevExpress.ExpressApp.StateMachine;
              using DevExpress.ExpressApp.StateMachine.NonPersistent;
              using System;
              using System.Collections.Generic;
              using System.Linq;
              using System.Text;
              using System.Threading.Tasks;
              namespace XAFStateMachineDemo.Module.BusinessObjects
              {
                 public class PurchaseRequestStatusStateMachine : StateMachine<PurchaseRequest>, IStateMachineUISettings
                 {
                     private IState startState;
                     public override string Name
                     {
                         get { return "Change status to"; }
                     }
                     public override string StatePropertyName
                     {
                         get { return "PurchaseRequestStatus"; }
                     }
                     public override IState StartState
                     {
                         get { return startState; }
                     }
                     public PurchaseRequestStatusStateMachine(IObjectSpace objectSpace) : base(objectSpace)
                     {
                         // Define states.
                         var draftState = new State(this, "Draft", PurchaseRequestStatusEnum.Draft);
                         var inProgressState = new State(this, "In Progress", PurchaseRequestStatusEnum.InProgress);
                         var pausedState = new State(this, "Paused", PurchaseRequestStatusEnum.Paused);
                         var canceledState = new State(this, "Canceled", PurchaseRequestStatusEnum.Canceled);
                         var approvedState = new State(this, "Approved", PurchaseRequestStatusEnum.Approved);
                         // Define state transitions.
                         draftState.Transitions.Add(new Transition(inProgressState) { SaveAndCloseView = true });
                         //draftState.Transitions.Add(new Transition(approvedState) { SaveAndCloseView = true });  // Has "intermediate" transitions (at a minimum, Draft -> InProgress -> Approved); do NOT show UI button
                         inProgressState.Transitions.Add(new Transition(pausedState) { SaveAndCloseView = true });
                         inProgressState.Transitions.Add(new Transition(canceledState) { SaveAndCloseView = true });
                         inProgressState.Transitions.Add(new Transition(approvedState) { SaveAndCloseView = true });
                         pausedState.Transitions.Add(new Transition(inProgressState) { SaveAndCloseView = true });
                         pausedState.Transitions.Add(new Transition(approvedState) { SaveAndCloseView = true });  // Has "intermediate" transitions (at a minimum, Paused -> InProgress -> Approved); show UI button
                         // Define target object criteria, if any are needed.
                         canceledState.TargetObjectCriteria = "Notes <> null";  // Make user enter notes if they want to cancel a purchase request.
                         //approvedState.TargetObjectCriteria = "TotalAmount > 0 && IsCurrentUserInRole('Admin')";  // Purchase request must have some non-zero, positive amount; check user if security is active.
                         approvedState.TargetObjectCriteria = "TotalAmount > 0";  // Purchase request must have some non-zero, positive amount.
                         // The following StateAppearance things do not necessarily make that much sense,
                         // and the colors are garish (should be lighter pastel shades in a real
                         // application) but these are just here in this demo solution to show how
                         // StateAppearance works. One should comment/uncomment the following lines of
                         // code to see how the StateAppearance stuff works…
                         // Define state appearance, if any are needed.
                         //StateAppearance inProgressAppearance = new StateAppearance(inProgressState);
                         //inProgressAppearance.TargetItems = "PurchaseRequestStatus";
                         //inProgressAppearance.BackColor = System.Drawing.Color.Blue;
                         //inProgressAppearance.TargetItems = "Description";
                         //inProgressAppearance.Enabled = false;
                         //StateAppearance pausedAppearance = new StateAppearance(pausedState) { TargetItems = "Description, PurchaseRequestStatus", BackColor = System.Drawing.Color.Yellow };
                         //StateAppearance canceledAppearance = new StateAppearance(canceledState) { TargetItems = "*", BackColor = System.Drawing.Color.HotPink };
                         //StateAppearance approvedAppearance = new StateAppearance(approvedState) { TargetItems = "PurchaseRequestStatus", BackColor = System.Drawing.Color.Green };
                         // Add states to state machine.
                         States.Add(draftState);
                         States.Add(inProgressState);
                         States.Add(pausedState);
                         States.Add(canceledState);
                         States.Add(approvedState);
                         // Set the start state.
                         startState = draftState;
                     }
                     // IStateMachineUISettings implementation begin.
                     public bool ExpandActionsInDetailView
                     {
                         get { return false; }  // Do not display state transition buttons at bottom of detail view (user will need to use the state transition menu) because confirmation message specified in the main module model editor is not applied to them.
                     }
                     // IStateMachineUISettings implementation end.
                 }
              }
              ==========
              using DevExpress.Data.Filtering;
              using DevExpress.ExpressApp;
              using DevExpress.ExpressApp.Actions;
              using DevExpress.ExpressApp.Editors;
              using DevExpress.ExpressApp.Layout;
              using DevExpress.ExpressApp.Model.NodeGenerators;
              using DevExpress.ExpressApp.StateMachine;
              using DevExpress.ExpressApp.SystemModule;
              using DevExpress.ExpressApp.Templates;
              using DevExpress.ExpressApp.Utils;
              using DevExpress.Persistent.Base;
              using DevExpress.Persistent.Validation;
              using System;
              using System.Collections.Generic;
              using System.Linq;
              using System.Text;
              using XAFStateMachineDemo.Module.BusinessObjects;
              using XAFStateMachineDemo.Module.Utility;
              namespace XAFStateMachineDemo.Module.Controllers
              {
                 public partial class PurchaseRequestDetailViewController : ViewController
                 {
                     PurchaseRequestStatusEnum purchaseRequestStatusLastPersistedValue;
                     public PurchaseRequestDetailViewController()
                     {
                         InitializeComponent();

              this.TargetViewType = ViewType.DetailView;
                         this.TargetObjectType = typeof(PurchaseRequest);
                     }
                     protected override void OnActivated()
                     {
                         base.OnActivated();

              var stateMachineController = this.Frame.GetController<StateMachineController>();
                         stateMachineController.TransitionExecuting += OnTransitionExecuting;
                         stateMachineController.TransitionExecuted += OnTransitionExecuted;
                     }
                     protected override void OnDeactivated()
                     {
                         base.OnDeactivated();
                         var stateMachineController = this.Frame.GetController<StateMachineController>();
                         stateMachineController.TransitionExecuted -= OnTransitionExecuted;
                         stateMachineController.TransitionExecuting -= OnTransitionExecuting;
                     }
                     private void OnTransitionExecuting(object sender, ExecuteTransitionEventArgs e)
                     {
                         PurchaseRequest pr = e.TargetObject as PurchaseRequest;  // Will be the PurchaseRequest business object BEFORE save to database.
                         purchaseRequestStatusLastPersistedValue = pr.PurchaseRequestStatus;
                     }
                     private void OnTransitionExecuted(object sender, ExecuteTransitionEventArgs e)
                     {
                         PurchaseRequest pr = e.TargetObject as PurchaseRequest;  // Will be the PurchaseRequest business object AFTER save to database.
                         HandleStateTransitions(purchaseRequestStatusLastPersistedValue, pr.PurchaseRequestStatus);
                         StringBuilder infoMsg = new StringBuilder();
                         infoMsg.Append("State transition completed for purchase request ");
                         infoMsg.Append(pr.Description);
                         infoMsg.Append(" going from ");
                         infoMsg.Append(purchaseRequestStatusLastPersistedValue);
                         infoMsg.Append(" state to ");
                         infoMsg.Append(pr.PurchaseRequestStatus);
                         infoMsg.Append(" state.");

              InfoMessageBox.Show(Application, infoMsg.ToString(), null);  // Example of using the InfoMessageBox class for informational-only type messages (cannot use for confirmation messages in web apps).
                     }
                     private void HandleStateTransitions(PurchaseRequestStatusEnum oldStatus, PurchaseRequestStatusEnum newStatus)
                     {
                         // Note that the methodology being used in this class to execute custom code
                         // on state transitions depends on setting property SaveAndCloseView = true on
                         // any transitions that will have custom code executed for them!
                         // Try to keep this code as "skinny" as possible, i.e., invoke other
                         // business objects/services to perform actual work (same philosophy as for
                         // ASP.NET MVC controllers, webforms event handlers, etc.).
                         // Only need to do something if the newStatus is not the same as the oldStatus.
                         // This may have been checked outside of this method but check it again here
                         // just to be absolutely sure.
                         if (newStatus != oldStatus)
                         {
                             // Detect which type of transition it is and take appropriate action. For
                             // example, when transitioning to the Paused status, perhaps we want to
                             // send an email to someone telling them that the PurchaseRequest has been
                             // put on pause. Or when the PurchaseRequest transitions to the Completed
                             // status, maybe we want to automatically create a PurchaseOrder from the
                             // PurchaseRequest.
                             // The decision code blocks here will usually correspond exactly or nearly
                             // exactly with the transitions that are defined in this business object's
                             // state machine class (in this case the PurchaseRequestStatusStateMachine
                             // class). Note that we could drill into the state machine object and its
                             // States and Transitions collections to find that info out programmatically,
                             // but at some point, the rubber hits the road and you just need to know what
                             // the particular transition is and what specific code to execute for that
                             // transition. (It should be possible to write a little program that would
                             // at least construct an initial version of the following if statements,
                             // either by drilling into the state machine object, or by reading the state
                             // machine's source code.)
                             if (oldStatus == PurchaseRequestStatusEnum.Draft)
                             {
                                 if (newStatus == PurchaseRequestStatusEnum.InProgress)
                                 {
                                     // Execute code for this transition, if any.
                                 }
                                 if (newStatus == PurchaseRequestStatusEnum.Approved)  // Has intermediate transitions
                                 {
                                     // Execute code for this transition, if any.
                                 }
                             }
                             if (oldStatus == PurchaseRequestStatusEnum.InProgress)
                             {
                                 if (newStatus == PurchaseRequestStatusEnum.Paused)
                                 {
                                     // Execute code for this transition, if any.
                                 }
                                 if (newStatus == PurchaseRequestStatusEnum.Canceled)
                                 {
                                     // Execute code for this transition, if any.
                                 }
                                 if (newStatus == PurchaseRequestStatusEnum.Approved)
                                 {
                                     // Execute code for this transition, if any.
                                 }
                             }
                             if (oldStatus == PurchaseRequestStatusEnum.Paused)
                             {
                                 if (newStatus == PurchaseRequestStatusEnum.InProgress)
                                 {
                                     // Execute code for this transition, if any.
                                 }
                                 if (newStatus == PurchaseRequestStatusEnum.Approved)  // Has intermediate transitions
                                 {
                                     // Execute code for this transition, if any.
                                 }
                             }
                         }
                     }
                 }
              }
              ==========

              WC WC
              Warren Connors 4 10 years ago

                Here is the VS2013 solution/project organization for the previous post's code, in attached screenshot.

                Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

                Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.