Current filter:
                                You should refresh the page.
                                Support Center
                                0
                                  • Hi,

                                    I'm creating a new project and want the New button to always show as a SimpleAction.

                                    I did something similar in a previous project (Q213904) but thought this time extending the existing NewObjectViewController would make more sense. The previous solution was quite messy.

                                    Unfortunately I am having a couple of silly problems with it where I don't understand the way the Views work fully.

                                    Anyway, I created a new ViewController called NewObjectViewController2 and derived that from NewObjectViewController. I added a SimpleAction to it called newObjectAction2 and set the appropriate properties.

                                    Below is the partial class showing what I have done:

                                        public partial class NewObjectViewController2 : NewObjectViewController
                                        {
                                            private const string ReasonKey = "NewObjectViewController2 active";

                                            public NewObjectViewController2()
                                            {
                                                InitializeComponent();
                                                RegisterActions(components);
                                            }

                                            protected override void UpdateActionState()
                                            {
                                                base.UpdateActionState();

                                                NewObjectAction.Active.RemoveItem(ReasonKey);
                                                newObjectAction2.Active.SetItemValue(ReasonKey, NewObjectAction.Active.ResultValue);
                                                NewObjectAction.Active.SetItemValue(ReasonKey, false);
                                            }

                                            private void newObjectAction2_Execute(object sender, SimpleActionExecuteEventArgs e)
                                            {
                                                Type type = null;
                                                if (View is ListView)
                                                    type = ((ListView)View).CollectionSource.ObjectTypeInfo.Type;
                                                if (View is DetailView)
                                                    type = View.CurrentObject.GetType();
                                                var args = new SingleChoiceActionExecuteEventArgs(e.Action, e.Action.SelectionContext, new ChoiceActionItem("NewObject", type));
                                                New(args);
                                            }
                                        }

                                    It is clear that adding the switching code to the UpdateActionSate method is not the way to go (or more is required). When this code is run the default NewObjectAction Active state is false because of EmptyItems. Where is this set (unset)?
                                    I had thought that the UpdateActionState method would get called again when the NewObjectAction Items were populated but this does not seem to be the case.
                                    What method should I add the switching code to, or which events should I hook into to perform the switch?

                                    Also, why (when I force newObjectAction2 to be visible) does the Execute event not display the new DetailView (it just seems to refresh the current View)?
                                    I've stepped through the source and it seems to configure everything correctly in the New method, it just doesn't change the View.

                                    This is a low priority as I have code that works, but I would like to understand why this doesn't work and how to make it work if possible.

                                    Thanks,

                                    Paul

                                0

                                Hi Paul,

                                First, you should inherit your controller from a platform-specific descendant of the NewObjectViewController (WebNewObjectViewController or WebNewObjectViewController), not from the base class. Then, to show a detail view, you should assign the ShowViewParameters object from the New method call to the corresponding action parameter. Specifically, as follows:

                                	
                                [C#]
                                private void newObjectAction2_Execute(object sender, SimpleActionExecuteEventArgs e) { ... New(args); e.ShowViewParameters.Assign(args.ShowViewParameters); }

                                If this does not help, please provide us with a small sample project, demonstrating your problem.

                                Thanks,
                                Michael.

                                0

                                Hi Michael,

                                Thanks for your tips. However, I'm looking for a platform neutral solution. Is it possible to do this with the base NewObjectViewController?

                                I regularly need to change or extend the default behavior, it is important that this functional code is part of the main module and doesn't have to be written twice (for Win and Web) or rely on ugly helper classes.

                                Thanks,

                                Paul

                                0

                                Hi Paul,

                                Inheriting from the base NewObjectViewController is not a viable solution. Since XAF creates all controllers that have no descendants, there will be two controllers (your controller and a built-in platform-specific controller) with overlapping actions and behavior.
                                Overriding the NewObjectViewController functionality from outside will not work in your instance, because the New method is not public, and if you deactivate NewObjectAction, you will not be able to execute it.

                                If you need to extend this controller, please consider handling its events, or implement new events in platform-specific descendants. To access your custom events implemented in descendant controllers, declare an interface with these events, and access them via this interface.

                                If any part of my response is unclear, please explain how exactly you plan to extend NewObjectViewController.

                                Thanks,
                                Michael.

                                0

                                Hi Michael,

                                Thanks for the info, I've inherited from the WebNewObjectViewController and the New action works fine.

                                However, the "Save and New" action is hidden. I can see this is because the DetailViewController checks the NewAction to see if it's Active and sets the SaveAndNewAction appropriately.

                                As I want to replace the "Save and New" SingleChoiceAction with a SimpleAction also, I added a new view controller deriving it from WebDetailViewController. I've basically duplicated the code from the NewObjectViewController2 (above), except in the UpdateActionState method, I set the NewObjectAction Active to true before running the base.UpdateActionState() and then set it back to false after. Unfortunately this causes a StackOverflowException in the base.UpdateActionState() method.

                                How do I get the Save and New action working?

                                Am I going about this all wrong? Is there a better way of replacing the SingleChoiceAction for New, Clone and "Save and New" with a SimpleAction?

                                My requirement is to simply not have the drop-down as the New, Clone and "Save and New" actions only ever have one item, so having a drop-down is unnecessary not to mention ugly and confusing for end users.

                                Thanks,

                                Paul

                                0

                                Hi Paul,

                                I recommend that you do not temporarily change the NewObjectAction activity because this may cause unwanted notifications. Instead, copy BoolList items one by one, except for your custom item. For example:

                                	
                                [C#]
                                protected override void UpdateActionState() { base.UpdateActionState(); foreach (string key in NewObjectAction.Active.GetKeys()) { if (key != "ReasonKey") { newObjectAction2.Active[key] = NewObjectAction.Active[key]; } } }

                                >>>Is there a better way of replacing the SingleChoiceAction for New, Clone and "Save and New" with a SimpleAction?
                                I am afraid there is no trivial solution for this task. So I think your approach is fine.

                                Thanks,
                                Michael.

                                0

                                Hi Michael,

                                Thanks, its very nearly working now. The only remaining problem is that the first time the DetailView is displayed the simple Save and New action is not visible. Querying the Active BoolList this is because EmptyItems is false.

                                My SimpleWebDetailViewController is configured as follows:

                                        protected override void OnActivated()
                                        {
                                            base.OnActivated();
                                            newObjectViewController = Frame.GetController<NewObjectViewController>();
                                        }

                                        protected override void UpdateActionState()
                                        {
                                            base.UpdateActionState();

                                            var newObjectActionActive = new BoolList();
                                            if (newObjectViewController != null)
                                            {
                                                foreach (string key in newObjectViewController.NewObjectAction.Active.GetKeys())
                                                {
                                                    if (key != SimpleWebNewObjectViewController.ReasonKey)
                                                        newObjectActionActive[key] = newObjectViewController.NewObjectAction.Active[key];
                                                }
                                            }
                                            foreach (string key in SaveAndNewAction.Active.GetKeys())
                                            {
                                                if (key == "NewObjectAction is active") simpleSaveAndNewAction.Active[key] = newObjectActionActive;
                                                else if (key != ReasonKey) simpleSaveAndNewAction.Active[key] = SaveAndNewAction.Active[key];
                                            }
                                            SaveAndNewAction.Active[ReasonKey] = false;
                                        }

                                Thanks,

                                Paul

                                0

                                Hi Paul,

                                This problem is caused by the fact that action items are populated outside the UpdateActionState method. To overcome this issue, handle the SaveAndNewAction.Active.Changed event to modify your action state. Please try the following code:

                                	
                                [C#]
                                public class SimpleWebNewObjectViewController : WebNewObjectViewController { public const string ReasonKey = "SimpleWebNewObjectViewController Active"; private SimpleAction simpleNewObjectAction; protected override void OnActivated() { base.OnActivated(); NewObjectAction.Active[ReasonKey] = false; } protected override void OnDeactivating() { NewObjectAction.Active.RemoveItem(ReasonKey); base.OnDeactivating(); } public SimpleWebNewObjectViewController() { simpleNewObjectAction = new SimpleAction(this, "New2", DevExpress.Persistent.Base.PredefinedCategory.ObjectsCreation); simpleNewObjectAction.Execute+=new SimpleActionExecuteEventHandler(newObjectAction2_Execute); } protected override void UpdateActionState() { base.UpdateActionState(); foreach (string key in NewObjectAction.Active.GetKeys()) { if (key != ReasonKey){ simpleNewObjectAction.Active[key] = NewObjectAction.Active[key]; } } } private void newObjectAction2_Execute(object sender, SimpleActionExecuteEventArgs e) { Type type = null; if (View is ListView) type = ((ListView)View).CollectionSource.ObjectTypeInfo.Type; if (View is DetailView) type = View.CurrentObject.GetType(); var args = new SingleChoiceActionExecuteEventArgs(e.Action, e.Action.SelectionContext, new ChoiceActionItem("NewObject", type)); New(args); e.ShowViewParameters.Assign(args.ShowViewParameters); } public SimpleAction SimpleNewObjectAction { get { return simpleNewObjectAction; } } } public class SimpleWebDetailViewController : WebDetailViewController { public const string ReasonKey = "SimpleWebDetailViewController Active"; SimpleWebNewObjectViewController newObjectViewController; SimpleAction simpleSaveAndNewAction; public SimpleWebDetailViewController() { simpleSaveAndNewAction = new SimpleAction(this, "SaveAndNew2", "Save"); } protected override void OnActivated() { newObjectViewController = Frame.GetController<SimpleWebNewObjectViewController>(); base.OnActivated(); SaveAndNewAction.Active[ReasonKey] = false; SaveAndNewAction.Active.Changed += new EventHandler<EventArgs>(Active_Changed); } void Active_Changed(object sender, EventArgs e) { foreach (string key in SaveAndNewAction.Active.GetKeys()) { if (key == "NewObjectAction is active" && newObjectViewController != null) { simpleSaveAndNewAction.Active[key] = newObjectViewController.SimpleNewObjectAction.Active.ResultValue; } else if (key != ReasonKey) { simpleSaveAndNewAction.Active[key] = SaveAndNewAction.Active[key]; } } } protected override void OnDeactivating() { SaveAndNewAction.Active.RemoveItem(ReasonKey); base.OnDeactivating(); } protected override void UpdateActionState() { base.UpdateActionState(); } }

                                Thanks,
                                Michael.

                                0

                                Thanks, excellent support as always, that works perfectly.

                                0

                                Hi,

                                Sorry to reactivate this issue, but it appears that very occasionally, the Active bool list of the main NewObjectAction is not replicated in the simpleNewObjectAction. It seems that the simpleNewObjectAction is created and displayed before all the view controllers have run. An instance of this is where I want the New button to display a pop-up window. In the view controllers OnActivated method I set the NewObjectAction.Active to false, so only the popupWindowNewObjectAction is displayed. However, although this Active state is recorded against the actual NewObjectAction, the simpleNewObjectAction has no record of it and is displayed as normal. Pressing Refresh fixes the problem.

                                What do I need to do to make sure the simpleNewObjectAction always copies the Active state of the NewObjectAction?

                                Thanks,

                                Paul

                                0

                                Hi Paul,

                                I am afraid the information you provided is not enough to replicate this issue. It is possible that you should use an approach, similar to the SaveAndNewAction - handle the action's Active.Changed event to copy BoolList items.
                                If this does not help, please provide us with a small sample project, reproducing the problem.

                                Thanks,
                                Michael.

                                To start a chat you should create a support ticket


                                If you need additional product information, write to us at info@devexpress.com or call us at +1 (818) 844-3383

                                FOLLOW US

                                DevExpress engineers feature-complete Presentation Controls, IDE Productivity Tools, Business Application Frameworks, and Reporting Systems for Visual Studio, along with high-performance HTML JS Mobile Frameworks for developers targeting iOS, Android and Windows Phone. Whether using WPF, Silverlight, ASP.NET, WinForms, HTML5 or Windows 8, DevExpress tools help you build and deliver your best in the shortest time possible.

                                Copyright © 1998-2014 Developer Express Inc.
                                All trademarks or registered trademarks are property of their respective owners