How To: Create Custom Document Actions

  • 11 minutes to read
  1. Assume that you have a PageGroup containing 2 Documents and a Page that can display any of these Documents separately. The objective is to display different Buttons within these Containers depending on the currently activated Document. Documents are generated based on the User Controls included in the project (see the Documents topic for details). To add a Document Action to this Document, implement the ISupportDocumentActions interface for the related User Control, as demonstrated in the code below.

    
    public partial class UserControl1 : UserControl, ISupportDocumentActions {
    }
    
  2. To implement an interface's methods, use the corresponding item from the Visual Studio pop-up menu.

    DocumentManager - ISupportDocumentAction Implementation

    The only ISupportDocumentActions interface method is ISupportDocumentActions.OnQueryDocumentActions. This method is called automatically, each time a related Document is activated. In this method, you can add custom DocumentAction objects to the IDocumentActionsArgs.DocumentActions collection. Add two Document Actions to the first Document.

    
    public void OnQueryDocumentActions(IDocumentActionsArgs args) {
        args.DocumentActions.Add(new DocumentAction(DoAction1) { Caption = "Action 1" });
        args.DocumentActions.Add(new DocumentAction(CanDoAction2, DoAction2) { Caption = "Action 2" });
    }
    
  3. Document Actions act like standard Windows Forms buttons. When creating an Action, you need to specify the execute method that implements the Action's functionality, and (optionally) the canExecute method, which specifies the set of criteria and checks whether or not the current Document meets these criteria. You can specify these methods as shown in the code below.

    
    void DoAction1(Document document) {
        . . .
    }
    
    bool CanDoAction2(Document document) {
        . . .
    }
    
    void DoAction2(Document document) {
        . . .
    }
    
  4. You now have two Document Actions that act like simple "push" buttons in your first Document. Actions can also act like check buttons that have two states - checked and unchecked. To create these Actions in your second Document, implement the ISupportDocumentActions interface (as you did before) and add two DocumentCheckAction objects to the IDocumentActionsArgs.DocumentActions collection.

    
    public void OnQueryDocumentActions(IDocumentActionsArgs args) {
        args.DocumentActions.Add(new DocumentCheckAction(() => flag, OnToggle) { Caption = "Flag" });
        args.DocumentActions.Add(new DocumentCheckAction(() => isSpecificState, OnCheck, OnUncheck) { Caption = "Specific State" });
    }
    

    In the code above, two different overloads are used to initialize DocumentCheckAction objects that act differently. Both Actions receive a Boolean variable as the first getState parameter. These variables store a Boolean value depending on the current Action's check state.

    
    public bool flag;
    public bool isSpecificState;
    

    The first Check Action receives the OnToggle method as the last parameter. This method takes a Document as the parameter and is executed each time the Action's check state changes.

    
    void OnToggle(Document document) {
        //do something
    }
    

    The 'Specific State' Check Action receives two methods - the OnCheck method is called when the Action is checked, and the OnUncheck method is called when the Action is unchecked. This allows you to perform different actions depending on the Action's check state. Compare this to the first Check Action, which performs the same actions whenever its check state changes.

    
    void OnCheck(Document document) {
        //First actions set
    }
    
    void OnUncheck(Document document) {
        //Second actions set
    }
    
  5. To display the Actions you have added, hide the default PageGroup header. To do so, set the IPageGroupDefaultProperties.ShowPageHeaders property to DefaultBoolean.False.

    
    pageGroup1.Properties.ShowPageHeaders = DevExpress.Utils.DefaultBoolean.False;
    

    The problem is that from now on, end-users can no longer navigate through PageGroup items because there are no page headers. To resolve this issue, add two Document Actions that will implement the navigation functionality. For these Actions, you will handle the WindowsUIView.QueryDocumentActions event. Both Document Actions are added at once, but since only one Document within a PageGroup can be activated, the canExecute method for only one corresponding Action will return true. Thus, both Actions will not be simultaneously visible.

    
    void windowsUIView1_QueryDocumentActions(object sender, QueryDocumentActionsEventArgs e) {
        WindowsUIView view = sender as WindowsUIView;
        if (e.Source == pageGroup1) {
            e.DocumentActions.Add(new DocumentAction((doc) => doc == document2,
                (doc) => view.ActivateDocument(document1)) { Caption = "Document 1" });
            e.DocumentActions.Add(new DocumentAction((doc) => doc == document1,
                (doc) => view.ActivateDocument(document2)) { Caption = "Document 2" });
        }
    }
    
    NOTE

    The WindowsUIView.QueryDocumentActions event (as well as the ISupportDocumentActions.OnQueryDocumentActions method) occurs only when the Document within a View is activated. Document Actions are most appropriate for PageGroup and Page containers, since only these containers have an activated Document at all times. SplitGroup and SlideGroup containers only have an activated Document in the Detail screen (see the WindowsUIView.ZoomLevel property). Normal and Overview screens for these containers cannot contain any Document Actions. Therefore, it is not recommended to use these Document Actions within these containers.

  6. Finally, the code below illustrates how to add the 'Hello' Document Action. This is an example of an Action that does not have a canExecute method, and thus is displayed within each Content Container.

    
    void windowsUIView1_QueryDocumentActions(object sender, QueryDocumentActionsEventArgs e) {
         e.DocumentActions.Add(new DocumentAction(Hello) { Caption = "Hello" });
     }
    
    void Hello(Document document) {
        MessageBox.Show("Hello from " + document.Caption);
    }
    
  7. The animation below shows the result. The Page container has different Actions depending on the activated Document (DocumentActions for the first Document and DocumentCheckActions for the second Document). The PageGroup container also changes its Actions when navigating through its items, and displays either 'Document 1' or 'Document 2' navigation Actions. The 'Hello' action is displayed within any Content Container regardless of the currently activated Document.

    DocumentManager - DocumentActions animation

Complete Example Code

This example demonstrates how to add How To: Create Custom Document Actions to your WindowsUIView application.

using System.Windows.Forms;
using DevExpress.XtraBars.Docking2010.Views.WindowsUI;
using WindowsFormsApplication1.ViewModels;

namespace WindowsFormsApplication1.Views {
    public partial class ucModuleA : UserControl, ISupportDocumentActions {
        ViewModelModuleA viewModel;
        public ucModuleA(ViewModelModuleA viewModel) {
            this.viewModel = viewModel;
            InitializeComponent();
        }
        #region ISupportDocumentActions Members
        public void OnQueryDocumentActions(IDocumentActionsArgs args) {
            args.DocumentActions.Add(new DocumentAction(DoAction1) { Caption = "Action 1" });
            args.DocumentActions.Add(new DocumentAction(CanDoAction2, DoAction2) { Caption = "Action 2" });
        }
        #endregion
        void DoAction1(Document document) {
            bool prev = viewModel.AllowAnotherAction;
            viewModel.DoSomeAction(); 
            MessageBox.Show("Some Action");
            if(!prev && prev != viewModel.AllowAnotherAction)
                MessageBox.Show("Action 2 enabled");
        }
        bool CanDoAction2(Document document) {
            return viewModel.AllowAnotherAction;
        }
        void DoAction2(Document document) {
            MessageBox.Show("Action 2 disabled");
            viewModel.ResetSomeAction();
        }
    }
}