Docstoc

dev cook book - MSDN Blogs

Document Sample
dev cook book - MSDN Blogs Powered By Docstoc
					    AX 2009 EP Dev Cookbook

    Contents
       Development Steps ................................................................................................................................... 4
       Task Page ( Info/New/Edit) ....................................................................................................................... 4
       Report Page............................................................................................................................................... 5
    Data Sets ....................................................................................................................................................... 5
           Init ......................................................................................................................................................... 5
           Pack/UnPack ......................................................................................................................................... 5
           Other Methods...................................................................................................................................... 5
           Args ....................................................................................................................................................... 5
       Data Sources ............................................................................................................................................. 7
           Init ......................................................................................................................................................... 7
           InitValue ................................................................................................................................................ 7
           ValidateWrite ........................................................................................................................................ 8
           Write ..................................................................................................................................................... 8
           <field>.datasetlookup ........................................................................................................................... 8
           <field>.modified .................................................................................................................................... 9
    Web Modules ................................................................................................................................................ 9
    Proxies ........................................................................................................................................................... 9
    Web Content Managed ............................................................................................................................... 10
    Page Definition ............................................................................................................................................ 10
    VS-AddIn...................................................................................................................................................... 10
    AXDataSourceControl ................................................................................................................................. 10
    AXGridView ................................................................................................................................................. 11
    AXForm........................................................................................................................................................ 11
    AxToolbar .................................................................................................................................................... 13
    Context ........................................................................................................................................................ 14
    Create the complete URL in code (based On eb Menu Items) ................................................................... 15
    Create a Page that has two webparts connected (master-detail) .............................................................. 16
           Prerequisites : ..................................................................................................................................... 16




                                                                                                                                                           Page 1
1
/
    AX 2009 EP Dev Cookbook
           Development :..................................................................................................................................... 16
       Add code to the consumer to get the provider’s record ........................................................................ 16
    AxPopup Control ......................................................................................................................................... 17
    Programatically reading data from AxDataSourceControl ......................................................................... 20
    Disabling Bound Fields through code ......................................................................................................... 21
    Aggregation in EP Datasets ......................................................................................................................... 22
    Create a custom filter in EP List page ......................................................................................................... 24
           With modification to the AOT-Dataset ............................................................................................... 24
           Without modification to the AOT-Dataset.......................................................................................... 25
    Use the infoLog ........................................................................................................................................... 25
    Hide Fields of defined in a AxGroup /AxForm ............................................................................................ 26
    Call any method on AX-server .................................................................................................................... 26
    Custom Lookup ........................................................................................................................................... 26
       Managed Code Custom Lookup .............................................................................................................. 26
       X++ Custom Lookup ................................................................................................................................ 27
    Page Title..................................................................................................................................................... 28
    Error Handling ............................................................................................................................................. 29
    View State ................................................................................................................................................... 29
    Access the Current Row / Field value ......................................................................................................... 30
    ExecuteQuery vs Research .......................................................................................................................... 31
    getfield vs. getfieldvalue ............................................................................................................................. 32
    Adding Javascript ........................................................................................................................................ 32
    Action Web Menu Item............................................................................................................................... 33
    Conditionally Making Grid Row Editable .................................................................................................... 33
    Workflow..................................................................................................................................................... 34
    Setting SharePoint Zone Width................................................................................................................... 34
    Enabling a toolbar menu item when a field is modified ............................................................................. 34
    Get the Bound field ..................................................................................................................................... 34
    Value Formatter .......................................................................................................................................... 34
    Validators .................................................................................................................................................... 35




                                                                                                                                                       Page 2
1
/
    AX 2009 EP Dev Cookbook
    App Shared logic ......................................................................................................................................... 35
    Correct a corrupt WebPage ........................................................................................................................ 36
    Get to the Enterprise Portal Library ............................................................................................................ 37
    Debugging ................................................................................................................................................... 37
       Debug X++ Code in EP ............................................................................................................................. 37
       Debug C# in User Controls ...................................................................................................................... 37
       Debug Framework Code ......................................................................................................................... 37
    64 bit machine deployment ........................................................................................................................ 38




                                                                                                                                                     Page 3
1
/
    AX 2009 EP Dev Cookbook
    Development Steps
      1. Create Tables/DataSets in AOT
      2. Create user control in Visual Studio using EP VS-Addin.
              a. Use the AXDataSourceControl to point to the DataSet created in Step 1.
              b. Use AxGridView or AXForm and the BoundFields to display data and make it editable
              c. Save the User Control and right click to Add to AOT. This should add the user control
                  under “Web -> Web Controls” node and created a node under “Web -> Web Content- >
                  Managed” and copied the .ascx and .ascx.cs file “%SYSTEM Drive:\Program
                  Files\Common Files\Microsoft Shared\Web Server
                  Extensions\12\TEMPLATE\LAYOUTS\ep” folder
      3. Create Page in SharePoint EP site and use Dynamics User Control web part and point to the User
         Control ( Web Content Item) Created in Step 2
      4. Create a Web Menu Item in AOT and point it to the Page created in Step 3
      5. Right Click the Web Menu Item and import. This should create a new item under “Web -> Web
         Files -> Page Definitions”
      6. Hook up the Web Menu Item in the right Web->Web Menu to be displayed either in the left
         navigation/quick launch or in the toolbar
      7. Set the appropriate security keys/config keys




    Task Page ( Info/New/Edit)
      1. Create one user control and switch the mode based on the web content parameter. Typically
         one control is created for Info and another one for both New/Edit. If your scenario permits you
         could create one web control for all the three. If it’s used for New/Edit , set the default to Edit.
      2. Create 3 web content items pointing one ( or two in case info is different from new/edit) web
         controls and 3 Web menu items ( 3 separate pages).
      3. Use the same dataset for all the three operations.
      4. View User Control Name must end with Info
      5. New/Edit User Control Name must end with AddEdit or not use any suffix
              a. If new and edit are done using different user controls then new must end with “Create”
                  and edit must end with “Edit”
      6. Same applies to Web Content and Web Menu Item as well
      7. Make sure the User Control is connected to the other parts in the page such as Title Part, Tool
         bar part etc.
      8. If the view page has factboxes, then use the “Header, Footer, 3 Columns Layout”. Set the
         second web part width to 30% using this code snippet. If it does not have any fact box, then use
         “Header,Left Column, Body” layout of Web Part Page.




                                                                                                   Page 4
1
/
    AX 2009 EP Dev Cookbook
    Report Page
        (1) Create a web part page in EP that contains the AX reports web part which points to the report
        (2) The Report Web Menu Item name must end with Report
        (3) Use “Header,Left Column, Body” layout of Web Part Page.




    Data Sets
             Init

             For checking arguments passed from managed code or context and adding ranges/ modifying
    query.

    if (element.args().dataset() == tablenum(EPPriceCalc))
        {
            epPriceCalc = element.args().record();
            custTable = CustTable::find(epPriceCalc.AccountNum);
            priceTransferParmId = epPriceCalc.ParmId;
        }



    Pack/UnPack
    Persisting values of in-memory variables between postbacks

    public container pack()
    {
        return [#CurrentVersion, #CurrentList] + [super()];
    }
    public boolean unpack(container _pack)
    {
        Integer     version = conpeek(_pack,1);
        container   base;
        boolean     ret;

        switch (version)
        {
            case #CurrentVersion          :    [version, #currentList, base] = _pack;
                                               ret = super(base);
                                               break;
              default: super(_pack);
        }

        return ret;

    }

    Other Methods
    Also common methods that could be called from Managed code or from other methods in the Data
    sources could be added at the DataSet level.

    Args
             Get external arguments through the args objects


                                                                                                  Page 5
1
/
    AX 2009 EP Dev Cookbook
          Checking for RecordContext

    public void init()
    {
        ;

        super();
        EPPersonalize::find(curuserid());
        if (element.args() && element.args().dataset() == tablenum(EmplTable))
        {
            callerEmplTable = element.args().record();
            emplId = callerEmplTable.EmplId;
        }

    }
          Passing parameters from Managed code to X++ in dataset

    protected void Page_Init(object sender, EventArgs e)
    {
    this.AxDataSource1.CreatingDataSetRun += new
    EventHandler<CreatingDataSetRunEventArgs>(AxDataSource1_CreatingDataSetRun);
    }
    Set the param value           to the event arugments
    void AxDataSource1_CreatingDataSetRun(object sender, CreatingDataSetRunEventArgs e)
    {
    e.DataSetRunArgs.parm = "4000";
    }

    In AOT override or add method in the data set and use element.args().parm() to
    received the paramter
    public void executeQuery()
    {
      QueryBuildRange             custRange;
      ;
             custRange = SysQuery::findOrCreateRange(this.query().dataSourceNo(1),
    fieldnum(CustTable, AccountNum));
             custRange.value(element.args().parm());
        super();
    }
    You can also pass an Enum. For example
    void AxDataSource1_CreatingDataSetRun(object sender, CreatingDataSetRunEventArgs e)
    {
    e.DataSetRunArgs.parmEnumType = EnumMetadata.EnumNum(this.AxSession, "EPFormAction");
    e.DataSetRunArgs.parmEnum(2);
    }

    public void init()
    {
        super();
          if (element.args().parmEnumType() == enumnum(EPFormAction) &&
    element.args().parmEnum() == EPFormAction::CreateMode)
        {
             //do somethign here
        }
    }




                                                                                   Page 6
1
/
    AX 2009 EP Dev Cookbook
    Data Sources
    Set the below properties at the individual datasources.

    InsertAtEnd : No
    InsertIfEmpty : No

    Also set Allow* properties on the Data source appropriately. For Data Effective data sources set the ValidTime* properties.


    Init
    Adding ranges
    public void init()
    {
         super();

        // Need a workaround to get count(*) more efficiently using the record id during
    insert
        if (element.args().parmEnumType() == enumnum(EPFormAction) &&
    element.args().parmEnum() == EPFormAction::CreateMode)
        {

    smmOpportunityTable_ds.query().dataSourceName(tablestr(smmOpportunityTable)).addRange(
    fieldnum(smmOpportunityTable,RecId)).value(SysQuery::value(0));
        }
    }

    public void init()
    {
        super();

        qbrName =
    this.query().dataSourceTable(tablenum(InventDimCombination)).addRange(fieldnum(InventD
    imCombination,Name));
        qbrName.status(RangeStatus::Hidden);

          qbrItem =
    this.query().dataSourceTable(tablenum(InventDimCombination)).addRange(fieldnum(InventD
    imCombination,ItemId));
          qbrItem.status(RangeStatus::Hidden);
    }
    Setting temporary table mode
    public void init()
    {
          super();
          //BP Deviation documented
          salesTable.setTmp();
    }

    InitValue
    Initializing values

    public void initValue()
    {
        super();

        // Is form called with a record




                                                                                                                        Page 7
1
/
    AX 2009 EP Dev Cookbook
         if (element.args() && element.args().record())
         {
             callerRecord = element.args().record();
             // Init opportunity from lead record
             if (callerRecord.TableId == tablenum(smmLeadTable))
             {
                 smmCreateEntity::initFromCommon(callerRecord, smmOpportunityTable);
                 info(DirParty::toolTip(smmOpportunityTable));
             }
         }
    }

    ValidateWrite
    For validation that are specific to the dataset. ( common table level validation could be at the table level)

    public boolean validateWrite()
    {
        #VendRequest
        boolean ret;

         ret = super();

         if   (ret && !VendTable::find(vendrequest.AccountNum))
              ret = checkFailed(strfmt("@SYS301682",vendrequest.AccountNum));

        if (ret && element.args().managedContentItemName() ==
    #VendRequestStatusChangeAddEdit &&
                DirPerson::find(vendRequest.ContactParty) == null)
            ret = checkFailed(strfmt("@SYS301683",vendrequest.ContactParty));

         return ret;
    }

    Write
    For updating tables not in the data set and reread

    public void write()
    {

         if (purchLine.RecId)
         {
             purchLine.InventDimId = InventDim::findOrCreate(inventDim).InventDimId;
             purchLine_ds.setCurrentInventDim();

             mapLines.insert(purchLine.RecId, purchLine);
         }
         super();
    }

    <field>.datasetlookup
    For Customizing field lookup. This does not appear in the override method list. But you should be able to
    manually create this method which will act as override.

    void dataSetLookup(SysDataSetLookup sysDataSetLookup)
    {
        List          list;
        Query         query;




                                                                                                       Page 8
1
/
    AX 2009 EP Dev Cookbook

        args = new Args();
        list = new List(Types::String);
        list.addEnd(fieldstr(ProjTable, ProjId));
        list.addEnd(fieldstr(ProjTable, Name));
        list.addEnd(fieldstr(ProjTable, Status));
        sysDataSetLookup.parmLookupFields(list);
        sysDataSetLookup.parmSelectField('ProjId');

        // Call query
        query = projTimeSheet_ds.getProjectIDQuery();

        // Pass the query to SysDataSetLookup so it result is rendered in the lookup page.
        sysDataSetLookup.parmQuery(query);
    }

    <field>.modified
    public void modified()
    {
        super();

        purchLine.modifyItemDim(inventDim,
            fieldnum(InventDim,ConfigId),
            InventTable::itemProductDimensionGroup(purchLine.ItemId));
        purchLine_ds.setCurrent();
    }



    Web Modules
        1. Create your module as a sub module to Home. Do not create it as a sibling to Home module.
        2. Set the QuickLaunch and MenuItemName property. Both are required for the module to work
        3. To get this new module in an existing EP site, mark that EP site as the Dev AOT site in the
           WebSites form in AX client and right click on the newly created module and deploy. Note you
           can only deploy the web module once. It won’t redeploy if that subsite already exists.
        4. After deploying reset IIS and AOS for it to appear in the top nav.


    Proxies
    If you would like to use your table methods or X++ classes or Enums in managed code, you should add
    them to proxies file under AOT\Web\Web Files\Static Files\Proxies. Typically Proxies are used if you
    need to access or update data that’s outside of Dataset or you would like to reuses some business logic
    in both Client and EP.

    /table:EmplTable
        /method:EmplTable.find

    /enum:TrvExpType
    /class:EPTrvItemization
        /method:EPTrvItemization.insertItemizedLines




                                                                                                   Page 9
1
/
    AX 2009 EP Dev Cookbook
    After changing the Proxies file, you can generate the proxies file using Tools->Development Tools ->
    Development Tools-> Web Development -> Proxies Or by clicking the Update button in Manage
    deployment UI.


    Web Content Managed
    Make sure to set the right Label/HelpText.
    WebConfigurationKey is generally set to EP and ConfigurationKey to the application specific key.

    EPFormAction is a commonly used EnumTypeParameter to be used inside the web control to determine
    the mode.


    Page Definition
    Set PageTitle to a label. Generally its <Action><Entity> for example New Customer

    UseContext – Generally set to true for Task pages which requires record context in the query string

    ParentPage – List page is set as the parent page for the task pages. This is used by the Breadcrumb
    control in EP.


    VS-AddIn
        1. Add a new user control and name it correctly before saving it to AOT.
        2. If you are renaming the control, make sure the code behind file and it’s reference in the markup
           are corrected before saving to AOT.
        3. Make sure the user control saved is available at C:\Program Files\Common Files\Microsoft
           Shared\Web Server Extensions\14\TEMPLATE\LAYOUTS\ep after you added to AOT and clicked
           the Save button in VS.
        4. If you are using proxy files then right click on the app_code folder in vs and “Generate Proxies”
           to include all the proxy files in your vs project for testing
        5. If you are going to test the control in VS and would like to use the EP stylesheets to see how it
           would look when it’s deployed to EP , right click on the project node and “Import Style Sheets”
        6. If your user control embeds other user control for example AxBaseUserControl add that control
           to your VS project




    AXDataSourceControl
    Make sure only one AXDataSourceControl has Role property set to Provider ( or ProviderConsumer) in
    your user control. If the user control contains other user control then across all these , only one
    datasourcecontrol should play the provider role.



                                                                                                   Page 10
1
/
    AX 2009 EP Dev Cookbook
    Always set EnableViewState and PersistState to True( This is the default. Don’t change it)


    AXGridView
        1. DataKeyNames must point to a one (or set) of unique fields int the DataSetView.
        2. If the user control is playing the Provider Role ( a propert on the AX user control webpart) , then
           at least one AXDataSourceControl should have the Role property set to Provider or
           ProviderConsumer and the ProviderView is set.


    AXForm
        1. Make Sure DataKeyNames set correctly.
        2. When Fields are selected for AXGroup using the boundfield designer, sometime the
           selectedfields are updated to the markup. (Known bug). Update the markup directly and add the
           boundfields.
        3. If the same Axform control is used for different modes than use the EPFormAction parameter
           set on the WebContent and switch to the right mode
        4. Set the DataMember to <DataSetView>_Current
        5. UpdateOnPostBack is generally set to False. If you need to access the field values entered in the
           control before the record is persisted in a postback, then set it to true. For example if you want
           to change the lookup of a second control based on the value entered on the first control, then
           you would need to set this property.
        6. If you are using the Form for Edit operation set AutoGenerateEditButton to true.



    protected void Page_Init(object sender, EventArgs e)
        {

            this.SetupMode();
        }
    private void SetupMode()
        {
            switch (this.FormMode)
            {
                case ApplicationProxy.EPFormAction.EditMode:
                    if (this.PageDefinition != null)
                    {
                        this.PageDefinition.pageTitle = Labels.GetLabel("@SYS131104");
                    }
                    this.formVendRequestProfileEdit.DefaultMode = DetailsViewMode.Edit;
                    this.formVendRequestProfileEdit.AutoGenerateEditButton = true;
                    break;

                default:
                    this.formVendRequestProfileEdit.DefaultMode =
    DetailsViewMode.ReadOnly;
                    break;
            }




                                                                                                     Page 11
1
/
    AX 2009 EP Dev Cookbook
        }
       7. Derive from AxBaseUserControl if the AxForm control requires RecordContext and should not
          display any data when there is no record Context.

    <%@ Register Src="AxBaseUserControl.ascx" TagName="AxBaseUserControl" TagPrefix="Ax"
    %>
    protected override bool RequiresExternalContext
        {
            get
            {
                if (this.FormAction == AppProxy.EPFormAction.CreateMode)
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
        }


       8. Some useful code generally used in AXForm controls

    //Web part private
        AxBaseWebPart _baseWebpart = null;

        //Webpart
        AxBaseWebPart BaseWebpart
        {
            get
            {
                //return the basewebpart if it is not null
                if (this._baseWebpart != null)
                    return this._baseWebpart;
                //get the webpart if basewebpart is null
                this._baseWebpart = AxBaseWebPart.GetWebpart(this);
                return this._baseWebpart;
            }
        }
        //Web part managed content item for the page
        Proxy.WebManagedContentItem ContentItem
        {
            get
            {
                //get the managed content item from the webpart
                return this.BaseWebpart == null ? null :
    this.BaseWebpart.WebManagedContentItem;
            }
        }
    private Boolean IsCustomer()
        {
            bool isCustomerBool = false;
            if (ApplicationProxy.EP.isCustomer(AxSession.AxaptaAdapter))
            {
                isCustomerBool = true;

            }
            return isCustomerBool;
        }



                                                                                             Page 12
1
/
    AX 2009 EP Dev Cookbook
    static AxBoundField GetField(DataControlFieldCollection fields, string name)
        {
            foreach (DataControlField field in fields)
            {
                AxBoundField boundField = field as AxBoundField;
                if (boundField != null && String.Compare(boundField.DataField, name, true)
    == 0)
                {
                    return boundField;
                }
            }
            return null;
        }




    AxToolbar
    SetMenuItemProperties, ActionMenuItemClicking, and ActionMenuItemClicked are AxToolbar control-specific
    events. You use SetMenuItemProperties to change the behavior of drop-down menus, such as showing or
    hiding menu items based on the currently selected record, setting or removing context, and so on.

                void Webpart_SetMenuItemProperties(object sender, SetMenuItemPropertiesEventArgs e)
                    {
                        // Do not pass the currently selected customer record context, since this menu is for
                creating new (query string should be empty)
                        if (e.MenuItem.MenuItemAOTName == "EPCustTableCreate")
                            ((AxUrlMenuItem)e.MenuItem).MenuItemContext = null;
                    } void webpart_ActionMenuItemClicking(object sender, ActionMenuItemClickingEventArgs e)
                    {
                        if (e.MenuItem.MenuItemAOTName.ToLower() == “EPCustTableDelete”)
                        {
                            e.RunMenuItem = false;
                        }
                    }




                void webpart_ActionMenuItemClicked(object sender, ActionMenuItemEventArgs e)
                    {
                   if (e.MenuItem.MenuItemAOTName.ToLower() == “EPCustTableDelete”)
                        {
                                int selectedIndex = this.AxGridView1.SelectedIndex;
                                if (selectedIndex != -1)
                                {
                                    this.AxGridView1.DeleteRow(selectedIndex);
                                }
                        }
                    }



    different options in toolbar customization

    void Webpart_SetToolbarMenuItemProperties(object sender,
    SetMenuItemPropertiesEventArgs e)
        {
            // Remove the menu item context (query string will be empty)
            if (e.MenuItem.MenuItemAOTName == "tutorial_CustomerCreate")




                                                                                                       Page 13
1
/
    AX 2009 EP Dev Cookbook
                   ((AxUrlMenuItem)e.MenuItem).MenuItemContext = null;

              // Set a client script for a top level button
              if (e.MenuItem.MenuItemAOTName == "SysFlushAOD")
                  e.MenuItem.ClientOnClickScript = "alert('hello refresh aod')";

              // Hide the whole drop down
              if (e.MenuItem.MenuItemAOTName == "EPSalesTableList" && e.IsDefaultMenuItem)
                  e.MenuItem.Hidden = true;

              // Change menu item text and help text
              if (e.MenuItem.MenuItemAOTName == "tutorial_CustomerEdit")
              {
                  e.MenuItem.DisplayName = "Edit My Customer";
                  e.MenuItem.HelpText = "My Customer Help Text";
              }
         }



    Context
    Context is a data structure used to share data related to the current environment and user actions
    taking place with different parts of a Web application. Context lets you know what’s happening in one
    control so you can react to it via another control or Web part, or pass that information to a new page.
    Generally, information about the current record the user is working on forms the context. For example,
    when the user selects a row in a grid view, other controls might need to get information about the
    newly selected row to react.

    AxContext is an abstract class that encapsulates the concept of the context. AxTableContext and
    AxViewContext derive and implement AxContext. AxTableContext is for table-based context, and AxViewContext
    is for data set view context. A view can contain more than one table, so it contains an AxTableContext
    object for each table in the view in the TableContextList collection. The RootTableContext property returns
    the TableContext of the root table in that data set view. AxViewDataKey uniquely identifies the
    AxViewContext, and it contains the TableDataKeys collection. AxTableDataKey uniquely identifies
    AxTableContext. An event is raised whenever the context changes. If the context is changed within the
    Web User Control, the CurrentContextChanged event is raised. If the context changes from other Web parts
    that are connected to it, the ExternalContextChanged event is raised.

    You can write code in these events on the AxBaseWebPart from your Web User Control and use the
    CurrentContextProviderView or ExternalContextProviderView and ExternalRecord properties to get the record
    associated with the context. You can all fire these events programmatically from your application logic
    by calling FireCurrentContextChanged or FireExternalContextChanged so that all other connected controls could
    react to the change you made through your code.

    To get the context object use the below

    IAxContext context = AxContextHelper.FindIAxContext(this );
    instead of
    private ISession AxSession
        {



                                                                                                       Page 14
1
/
    AX 2009 EP Dev Cookbook
             get
             {
                    AxBaseWebPart webpart = AxBaseWebPart.GetWebpart(this);
                    return webpart == null ? null : webpart.Session;
             }
        }
    Following is sample code to fire the CurrentContextChanged event.

    void CurrentContextProviderView_ListChanged(object sender,
    System.ComponentModel.ListChangedEventArgs e)
        {   AxBaseWebPart webpart = this.WebPart;        // The current row (which is the
    current context) has changed - update the consumer webparts.Fire the current context
    change event to refresh (re-execute the query) the consumer webparts
                webpart.FireCurrentContextChanged();
            }
    Sample code for getting the record from the connected Web part follows. First subscribe to the
    ExternalContext Changed event in the consumer Web User Control, as here.

                  protected void Page_Load(object sender, EventArgs e)
                      {
                     //Add Event handler for the ExternalContextChange event. Whenever the selecting the grid
                  of the provider webpart changes, this event will get fired.

                          (AxBaseWebPart.GetWebpart(this)).ExternalContextChanged += new
                  EventHandler<Microsoft.Dynamics.Framework.Portal.UI.AxExternalContextChangedEventArgs>(AxCont
                  extConsumer_ExternalContextChanged);
                  }




    Then get the record passed through the external context, as shown here.

                      void AxContextConsumer_ExternalContextChanged(object sender,
                  Microsoft.Dynamics.Framework.Portal.UI.AxExternalContextChangedEventArgs e)    {        //Get
                  the AxTableContext from the ExternalContext passed through web part connection and construct
                  the record object        //and get to the value of the fields        IAxaptaRecordAdapter
                  currentRecord = (AxBaseWebPart.GetWebpart(this)).ExternalRecord;        {
                     if (currentRecord != null)
                              {
                     lblCustomer.Text = (string)currentRecord.GetField("Name");
                              }
                          }
                      }




    Create the complete URL in code (based On eb Menu Items)
                 protected override void OnPreRender(EventArgs e)
                 {
                     // Gets the current view to the record selected in the dropdown
                     DataSetView view = dsSales.GetDataSourceView(ddSales.DataMember).DataSetView;
                     DataSetViewRow row = view.GetCurrent();

                     // Get the url for the webpage that referenced the current record
                     // In the sample an extra method was made for this




                                                                                                         Page 15
1
/
    AX 2009 EP Dev Cookbook
                       AxUrlMenuItem url = new AxUrlMenuItem("EPSalesTableInfo");
                       // Set the record context on the URL so we can open the pge for a specific record
                       DataSourceMetadata metaData = this.dsSales.Metadata.DataSources[ddSales.DataMember];
                       AxTableContext context = AxTableContext.Create(row.GetDefaultTableDataKey(metaData));
                       url.MenuItemContext = context;

                       // update teh hyperlink to point to the url
                       hpRecord.NavigateUrl = url.Url.ToString();

                       base.OnPreRender(e);
                  }




    Create a Page that has two webparts connected (master-detail)
    A page in EP can contain multiple web parts that display related data. To make this work, web part
    communication must be set up between the two parts. One User Control will act as a publisher; the
    other(s) will act as subscriber(s).

    Prerequisites :
    The tables should have relationship defined at the table level or Extended Data Types must been set up for the key fields that
    will be used for the AxContextList.They must have relations defined that link the field to its corresponding table.

    Development :
    Configuration for ‘publishers’ in VS 2008
           o Locate the Ax-Control that will be publishing the AxContextList.
                Example : AxGridview
           o Set the DataKeyNames property to contain the key fields that uniquely identify the record being published
    Configuration for ‘subscribers’ in VS 2008
           o Locate the Ax-Control that will subscribe to the AxContextList.
                Example : AxForm
           o Set the DataKeyNames property to contain the key fields that uniquely identify the record being subscribed to
           o Set the Datamember (typically the xx_current)
    Configuration in Sharepoint
           o The role property of the ‘publisher’ must be set to Provider
           o The role property of the ‘subscriber’ must be set to Consumer
           o Link the 2 webparts by clicking the Connections and the ‘Get AxContextList From’ (or the other way around, and
                then use the ‘Send AxContextList To’)



    Add code to the consumer to get the provider’s record
    In the example below, a Ax User Control will be defined as Consumer in Sharepoint. A simple label will
    display information about the master (provider). Thus this control must be notified when the master
    changes.

    In VS 2008
           o Create a new Ax User Control
           o Drag and drop a Label to the form, set the ID to labInfoField
           o Change the code in the code-behind file analog to the following :




                                                                                                                         Page 16
1
/
    AX 2009 EP Dev Cookbook
           using Microsoft.Dynamics.Framework.Portal.UI;
           using Microsoft.Dynamics.Framework.BusinessConnector.Adapter;

           public partial class AAP2EmpDetail2 : System.Web.UI.UserControl
           {
               protected void Page_Load(object sender, EventArgs e)
               {
                   // Add Event handler for the ExternalContextChanged event
                   // whenever the selecting in the grid of the provider webpart changes,
                   //   this event will get fired
                   (AxBaseWebPart.GetWebpart(this)).ExternalContextChanged +=
                       new EventHandler<AxExternalContextChangedEventArgs>(
                                           AxContextConsumer_ExternalContextChanged
                       );
               }

                void
               AxContextConsumer_ExternalContextChanged(object sender, AxExternalContextChangedEventArgs e)
                {
                     // Get the External record from the context passed through ep part connection
                     // and get the the value of the fields
                     IAxaptaRecordAdapter currentRecord = (AxBaseWebPart.GetWebpart(this)).ExternalRecord;
                     if (currentRecord != null)
                          labInfoField.Text = (string)currentRecord.GetField("LastName"); //
                     else
                          labInfoField.Text = "";
                }
           }




    AxPopup Control
    AxPopup controls are used to open a page in a popup browser window and upon closing a popup page,
    pass data from the popup page back to the parent page and trigger an OnPopupClosed server event on
    the parent. This functionality is encapsulated in two controls - AxPopupParentControl to be used in the
    parent page and AxPopupChildControl to be used on the popup page. They both derive from
    AxPopupBaseControl. These controls are AJAX-compatible, so they can be created conditionally as part
    of a partial update.

    Data can be passed from the popup page back to the parent page using AxPopupField objects. They are
    exposed via the Fields property of the AxPopupBaseControl, from which both AxPopupParentControl
    and AxPopupChildControl are derived.

    AxPopupParentControl and AxPopupChildControl have fields with the same names. When the popup
    page closes, the value of each field of the AxPopupChildControl is assigned (via client-side script) to the
    correspondent field in the AxPopupParentControl.

    AxPopupField can optionally be associated with another control, such as TextBox or any other control,
    by assigning its TargetId property to the ID property of the target control. This is useful, for instance,
    when the popup page has a TextBox control. In order to pass the user input to the parent page upon
    closing the popup, and to do it entirely on the client hence avoiding the round trip, a field needs to be
    associated with the TextBox control.



                                                                                                      Page 17
1
/
    AX 2009 EP Dev Cookbook
    In AX 2009 this approach is used in number of places and one such control is the Business Relations list.

    The AxPopupField control is placed in the user control displaying the list. In the code behind, the toolbar
    action calls the popup using the GetOpenPopUpEventReference method. Both the parent control and
    the childcontrol uses the field with the same name hiddenCustomerAccountNo to pass the values
    back& forth. The childcontrol gets the value from the text box using the TargetControlID.




    smmBusRelListGrid.ascx
    List containing the ParentControl from the popup
    <dynamics:AxPopupParentControl ID="PopupConvertCustomer" runat="server"
    PopupHeight ="180" PopupWidth="400" >
        <dynamics:AxPopupField name="hiddenCustomerAccountNo" />
    </dynamics:AxPopupParentControl>
    smmBusRelListGrid.ascx.cs
    Code behind opening up the popup using GetOpenPopUpEventReference
    protected void AddCustomerAccountNoScript(SetMenuItemPropertiesEventArgs e,
    string custAccount)
        {
            AxUrlMenuItem menuItem = new AxUrlMenuItem(CUSTOMER_ACCOUNT_DIALOG);
            DataSetViewRow row = this.GetCurrentDataSetViewRow();
            if (row != null)
            {
                AxTableContext context = AxTableContext.Create
                (row.GetTableDataKey(row.DataSetView.Metadata.RootDataSource,
    null));

                       menuItem.MenuItemContext = context;

                       //Adding the CustAccount QueryString variable
                       if (custAccount != string.Empty)
                       {



                                                                                                     Page 18
1
/
    AX 2009 EP Dev Cookbook
                           menuItem.ExtraParams.Add("CustAccount", custAccount);
                       }
                       menuItem.RemoveNavigation = true;

                //Calling the javascript function to set the properties of
    opening the customer account
                //on clicking the menu items.
                e.MenuItem.ClientOnClickScript =
    this.PopupConvertCustomer.GetOpenPopupEventReference(menuItem);
            }
        }
    CustomerAccountDialog.ascx
    The popup form transferring the value entered in the target to the parent control by using the same control name.
    <div>
        <br />
        <br />
        <table style="width: 100%">
            <tr>
                 <td class="PopoverFormText">
                     <asp:Label ID="lblCustAccount" runat="server" Text="<%$
    axlabel:@SYS7149 %>"></asp:Label>
                 </td>
                 <td class="PopoverFormText" >
                     <asp:TextBox ID="txtCustAccount" runat="server"
    MaxLength="20" ></asp:TextBox>
                     <dynamics:AxPopupChildControl ID="popupChild" runat="server">
                         <dynamics:AxPopupField name="hiddenCustomerAccountNo"
    TargetControlId="txtCustAccount" />
                     </dynamics:AxPopupChildControl>
                 </td>
            </tr>
            <tr><td colspan="3"><br /> <hr class="hr" />
                 </td></tr>
            <tr>
                 <td align="right" colspan="2">
                 <asp:Button id = "OkButton" CssClass="okCancelButton" runat
    ="server" Text="<%$ axlabel:@SYS5473 %>" onclick="OkButton_Click" />
                 <input id="CancelButton" class="okCancelButton" runat ="server"
    type="button" value="<%$ axlabel:@SYS50163 %>" onclick="window.close();" />

                 </td>
                 <td style="width: 10%"></td>
            </tr>
        </table>
    </div>

    CustomerAccountDialog.ascx.cs
    Pop up closed after validing the data entered in the popup , giving control
    back to the parent page.
    //Used to validate the CustAccount no etered.
        protected void OkButton_Click(object sender, EventArgs e)
        {
            try
            {
                if (this.txtCustAccount.Text.Equals(string.Empty))



                                                                                                                        Page 19
1
/
    AX 2009 EP Dev Cookbook
                   {
                         //Displaying error message: Account number is not specified
                         DisplayInfolog(InfoType.Error, "@SYS24085");
                         return;
                   }

                //Validating the Customer Account no. entered
                if
    (!ApplicationProxy.SmmOpportunityStatusUpdate.checkCustomerAccount(this.AxSes
    sion.AxaptaAdapter, this.txtCustAccount.Text))
                {
                    return;
                }

                   //Calling the script for closing the dialogbox
                   this.popupChild.ClosePopup(true, true);
            }
            catch (Exception ex)
            {
                AxExceptionCategory exceptionCategory;
                // This returns true if the exception can be handled here
                if (!AxControlExceptionHandler.TryHandleException(this, ex, out
    exceptionCategory))
                {
                    // The exception was fatal - in this case we re-throw.
                    throw;
                }
            }
        }




    Programatically reading data from AxDataSourceControl
    DataSourceControl makes it simple to get Ax data and display it in DataBound UI controls and
    manipulate the data. You can also use them to read data programtically. Below is one way of doing it.
    The other way to get Ax data programatically is to get the DataSet directly using MetaDataCahce object
    and reading data.



    private void GetData()
          {

                DataSourceViewSelectCallback callback = new
    DataSourceViewSelectCallback(PrintData);
                  AxDataSource1.GetDataSourceView("CustTable").Select(DataSourceSelectArgu
    ments.Empty,callback);

           }

        private void PrintData(IEnumerable data)
        {
            IEnumerator i = data.GetEnumerator();




                                                                                                  Page 20
1
/
    AX 2009 EP Dev Cookbook
            while (i.MoveNext())
            {
                Response.Write(DataBinder.Eval(i.Current, "AccountNum").ToString() +
    “<BR/>”);
            }
        }




    Disabling Bound Fields through code
    You can make a bound field as read only or hide the Lookupbutton of the bound field through code in
    the page load event.

    For example

    ...
    AxBoundField boundField = AxGridView1.Columns[i] as AxBoundField;
    boundField.ReadOnly = true;
    ...

    or

    ...
    AxBoundField boundField = AxGridView1.Columns[i] as AxBoundField;
    boundField.LookupButtonDisplaySettings = LookupButtonDisplaySettings.Never;
    ...

    If they do want to hide the lookup for specific rows, then they should use a template field instead of the
    AxBoundField. For example ,




    In the below code DataSet Name is DemoSet, Table Name is Table1 and FieldName is AccountNum

    <asp:TemplateField ConvertEmptyStringToNull="False"
                HeaderText="<%$ AxLabel:@SYS1996 %>" SortExpression="AccountNum">
                <EditItemTemplate>
                    <asp:TextBox ID="TextBox1" runat="server"
                        Columns="<%$ AxDataSet:DemoSet.Table1.AccountNum.DisplayLength %>"
                        Enabled="<%$ AxDataSet:DemoSet.Table1.AccountNum.AllowEdit %>"
                        MaxLength="<%$ AxDataSet:DemoSet.Table1.AccountNum.StringSize %>"
                        Text='<%# Bind("AccountNum") %>'></asp:TextBox>
                    <dynamics:AxLookup ID="AxLookup1" runat="server"
    DataLookupField="AccountNum"



                                                                                                    Page 21
1
/
    AX 2009 EP Dev Cookbook
                        DataSet="DemoSet" DataSetView="Table1" TargetControlId="TextBox1"
                        Visible="<%$ AxDataSet:DemoSet.Table1.AccountNum.AllowEdit %>">
                    </dynamics:AxLookup>
                </EditItemTemplate>
                <ItemTemplate>
                    <asp:Label ID="Label1" runat="server" Text='<%# Bind("AccountNum")
    %>'></asp:Label>
                </ItemTemplate>
            </asp:TemplateField>



    Code Behind to hide the lookup control conditionally and disable the cell

    protected void AxGridView1_RowDataBound(object sender, GridViewRowEventArgs e)
        {
            if (e.Row != null && e.Row.RowType == DataControlRowType.DataRow)
            {
           /* disable the thrid column which displays accountnum and hide the lookup if
    the second field value is 1
                DataSetViewRow dataRow = (DataSetViewRow)e.Row.DataItem;
                bool isInternalProject = dataRow.GetFieldValue("Field2").ToString() ==
    "1";

                    if (isInternalProject)
                    {
                        Control c = e.Row.Cells[2].FindControl("AxLookup1");
                        if ( c!= null)
                            c.Visible = false;
                        e.Row.Cells[2].Enabled = false;
                    }
               }




    Aggregation in EP Datasets

    Often times, you might want to display some aggregated values in a simple grid interface in a web page.
    Enterprise Portal provides a simple and efficient way of doing this. Here is a sample that I created ( with
    help from Ahmad, Sella and others) for a partner who has similar requirements to display aggregated
    values in EP grid.
    There are two ways to go about it. You can change the query of the dataset which has tables simply
    joined and change it to group by and aggregate fields through code or You can build AxQuery in AOT
    which has the group by and aggregate fields defined and then use this Ax Query in DataSet (Drag-n-Drop
    the Query to the DataSet or create a view pointing to the Query and refer this view through the table
    property)

    First approach: Changing the query through code
    1. Create a DataSet with two table ( CustTable and SalesTable) that are inner joined
    in AOT
    2. Override the init method of CustTable and SalesTable data source and write the
    below code
    3. Create a User control and point to the fields that are used in aggregation in the
    GridView and use it in the page




                                                                                                     Page 22
1
/
    AX 2009 EP Dev Cookbook




                              Page 23
1
/
    AX 2009 EP Dev Cookbook
    Second approach
    (1) Create a new Query in AOT
        a. Add the datasource
        b. Add the Group By column
        c.    Add the Fields ( the group by column and the aggregated values for other fields)
    (2) Create a new View in AOT
        a.    Set the Query property to the query created above
    (3) Create a new DataSet in aOT
        a.    Add the datasource and set the Table property to the View created about

    You could also directly drag-n-drop the Query to Data Source node of DataSet in AOT without creating a
    view


    Create a custom filter in EP List page
    With modification to the AOT-Dataset

    AOT : Changes to DataSet

    Add QueryBuildRange in DataDeclaration

           public class DataSetRun extends ObjectRun
           {
               QueryBuildRange qbrStateId;
           }


    Override init() –method of DataSource

           public void init()
           {
               super();

               qbrStateId = this.query().dataSourceTable(tablenum(AddressCounty))
                                   .addRange(fieldnum(AddressCounty, StateId));
           }
    Create method on DataSource to re-execute the query
           void SetFilterOnStateId(AddressStateId _stateId)
           {
               ;
               qbrStateId.value(QueryValue(_stateId));

           }


    Create a method on the DataSet that can be called from ASP.NET, and can call the method in de
    DataSource

           void SetFilterOnStateId(AddressStateId _StateId)
           {
               AddressCounty_ds.SetFilterOnStateId(_StateId);
               AddressCounty_ds.executeQuery();




                                                                                                 Page 24
1
/
    AX 2009 EP Dev Cookbook
           }

    VS : Call the filtering in AX

    (can be in a button_clicked(), onValueChanged(), or wherever)

           protected void btnSelectStateID_Click(object sender, EventArgs e)
           {
               // Call filter method in Ax-DataSet
               dsCaseCustFilter.GetDataSet().DataSetRun.AxaptaObjectAdapter
                        .Call("SetFilterOnStateId", txtSelectStateID.Text);
           }

    Without modification to the AOT-Dataset

    VS : Apply the filtering

    (can be in a button_clicked(), onValueChanged(), lookup_OkClicked(), or wherever)

           protected void btnSelectStateID_Click(object sender, EventArgs e)
           {
               DataSetView dsv = this.axDsIPICContract.GetDataSet().DataSetViews[0];
               dsv.UserFilter.ClearOpenFilter();
               Microsoft.Dynamics.Framework.Data.Ax.filterObject flt = new filterObject();
               flt.name = "ContractFilter";

               Microsoft.Dynamics.Framework.Data.Ax.conditionType typ = new conditionType();
               typ.__operator = Microsoft.Dynamics.Framework.Data.Ax.operatorType.eq;
               typ.status = Microsoft.Dynamics.Framework.Data.Ax.conditionStatus.open;
               typ.value = this.tbCompanyID.Text;
               typ.attribute = "CompanyId";
               flt.conditionCollection.Add(typ);

               dsv.UserFilter.Add(flt);
           }



    Use the infoLog
           using Proxy = Microsoft.Dynamics.Framework.BusinessConnector.Proxy;
           Proxy.Info objInfoLog = new Proxy.Info(this.AxSession.AxaptaAdapter);
           objInfoLog.add(Proxy.Exception.Warning, “Hello World!!!”);




                                                                                               Page 25
1
/
    AX 2009 EP Dev Cookbook




    Hide Fields of defined in a AxGroup /AxForm
            protected void AxFrmEmployee_PreRender(object sender, EventArgs e)
            {
                AxForm frm = this.axFrmEmployee;

                 for (int i = 0; i < this.AxGroup1.Fields.Count; i++)
                 {
                     AxBoundField fld = this.AxGroup1.Fields[i] as AxBoundField;
                     if ((fld != null) && (fld.Metadata.Name == "TitleId"))
                     {
                         fld.Visible = (frm.CurrentMode == DetailsViewMode.ReadOnly) ? false : true;
                     }
                 }
            }



    Call any method on AX-server
            Object o = AxBaseWebPart.GetWebpart(this).Session.AxaptaAdapter
                         .CallStaticClassMethod("ABC", "XYZ);



    Custom Lookup
    Managed Code Custom Lookup
    protected void Name_Lookup(object sender, AxLookupEventArgs e)
        {
            AxLookup nameLookup = e.LookupControl;
            string partyName = "*";

                try
                {
                // We set the lookup range based on either the name selected or "*"
                // We get the range value from the current view field value
                partyName =
    this.DataSourceView.DataSetView.GetCurrent().GetFieldValue("DirPartyTable!Name").ToStr
    ing();

                      // Create the lookup dataset - we will do a lookup in the DirPartyTable
    table
                using (Proxy.SysDataSetBuilder sysDataSetBuilder =
    Proxy.SysDataSetBuilder.constructLookupDataSet(this.AxSession.AxaptaAdapter,
    TableMetadata.TableNum(this.AxSession, "DirPartyTable")))
                {
                    // Set the run time generated data set as the lookup data set




                                                                                                       Page 26
1
/
    AX 2009 EP Dev Cookbook
                    nameLookup.LookupDataSet = new DataSet(this.AxSession,
    sysDataSetBuilder.toDataSet());
                }
                // DataSet has to be init'ed before accessing the data sources
                nameLookup.LookupDataSet.Init();

                // Filter the lookup
                using (Proxy.Query query =
    nameLookup.LookupDataSet.DataSetViews[0].MasterDataSource.query())
                {
                    // If the partyName is blank we assign the "*" as the range

    query.dataSourceNo(1).addRange(TableDataFieldMetadata.FieldNum(this.AxSession,
    "DirPartyTable", "Name")).value = String.IsNullOrEmpty(partyName) ? "*" : "*" +
    partyName + "*";
                }
                // Specify the lookup fields used
                // TODO: Temporary fix
                nameLookup.Fields.Add(AxBoundFieldFactory.Create(this.AxSession,
    nameLookup.LookupDataSetViewMetadata.ViewFields["EntityType"]));
                nameLookup.Fields.Add(AxBoundFieldFactory.Create(this.AxSession,
    nameLookup.LookupDataSetViewMetadata.ViewFields["Type**"]));
                nameLookup.Fields.Add(AxBoundFieldFactory.Create(this.AxSession,
    nameLookup.LookupDataSetViewMetadata.ViewFields["Name"]));

               // Specify the select field
               nameLookup.SelectField = "RecId";
            }
            catch (System.Exception ex)
            {
                AxExceptionCategory exceptionCategory;
                // This returns true if the exception can be handled here
                if (!AxControlExceptionHandler.TryHandleException(this, ex, out
    exceptionCategory))
                {
                    // The exception is system fatal - in this case we re-throw.
                    throw;
                }
            }
        }

    X++ Custom Lookup
    void dataSetLookup(SysDataSetLookup sysDataSetLookup)
    {
        List          list;
        Query         query;

        args = new Args();
        list = new List(Types::String);
        list.addEnd(fieldstr(ProjTable, ProjId));
        list.addEnd(fieldstr(ProjTable, Name));
        list.addEnd(fieldstr(ProjTable, Status));
        sysDataSetLookup.parmLookupFields(list);
        sysDataSetLookup.parmSelectField('ProjId');

        // Call query
        query = projTimeSheet_ds.getProjectIDQuery();

        // Pass the query to SysDataSetLookup so it result is rendered in the lookup page.
        sysDataSetLookup.parmQuery(query);




                                                                                   Page 27
1
/
    AX 2009 EP Dev Cookbook
    }




    Page Title
    First, you need to be using the Dynamics Page Title Web Part on the page (as opposed to the legacy title
    provider). Connect the Page Title Web Part to your user control.

    The Page Title Web Part will pick up 2 different things from the user control.

           Caption
               o Initial text that will always be displayed
           Context
               o Information specific to a record


    There are four properties that control the Page Title:

           Caption
               o Set the caption text directly
           ShowContext
               o Determine if page title displays any available context
           MenuItem
               o A URL that encompasses the entire Context
           View
               o DataSetView from which to retrieve the current context (record)


    Protected void Page_Load(object sender, EventArgs e)
    {
                    ITitleProvider titleProvider = AxBaseWebPart.GetWebPart(this) as
    ITitleProvider;

                    // If Caption is not provided, nothing will be shown. Basically, it
    can’t be null or empty
                    titleProvider.Caption = “Caption”;
                    // Determines if the context will link to any pages
                    titleProvider.MenuItem = new AxUrlMenuItem(“UrlMenuItem”);
                    // Determines if the context will be shown
                    titleProvider.ShowContext = false; // true by default
                    // Determines which data set view will provide the context
                    titleProvider.View = this.AxDataSource1.GetDataSet().DataSetViews[0];
    }



    Caption – TitleField1Label: TitleField1Value, TitleField2Value

    If the TitleField1 or 2 is SFK, then it will be replaced with it’s AutoIdentification field group.




                                                                                                         Page 28
1
/
    AX 2009 EP Dev Cookbook
    Error Handling
    In Enterprise Portal, BC.Net (including proxies), the metadata, and the data layer all throw exceptions in
    case of error conditions. The Enterprise Portal ASP.NET controls automatically handle these exceptions,
    taking appropriate actions and displaying the errors in Infolog.

    Exceptions in Enterprise Portal are divided into three categories. These exception categories are defined
    in the enumeration AxExceptionCategory:

               NonFatal The exception handling code should respond appropriately and allow the request to
                continue normally.
               AxFatal Indicates that an unrecoverable error has occurred in Enterprise Portal. Enterprise Portal
                content will not display. Content not related to Enterprise Portal should display as expected.
               SystemFatal Indicates that a serious error, such as out of memory, has occurred and the request
                must be aborted. Errors of this kind often cause an HTTP error code 500.
    If your code directly calls methods in data or metadata layers from Enterprise Portal or with proxy class
    calling X++ methods, it must handle these exceptions. The following code shows how to
    AxControlExceptionHandler in the try-catch statement to handle exceptions.

                 Try
                 {
                     // Code that may encounter exceptions goes here.
                 }
                 catch (System.Exception ex)
                 {   AxExceptionCategory exceptionCategory;
                     // Determine whether the exception can be handled.
                     if (AxControlExceptionHandler.TryHandleException(this, ex, out exceptionCategory) ==
                 false)
                     {
                         // The exception was fatal and cannot be handled. Rethrow it.
                         throw;
                     }
                     if (exceptionCategory == AxExceptionCategory.NonFatal)
                     {
                    // Application code to properly respond to the exception goes here.
                     }
                 }



    AxControlExceptionHandler tries to handle Dynamics AX exceptions based on the three exception categories
    just mentioned. It returns true if the exception is NonFatal.


    View State
    The Web is stateless, which means that each request for a page is treated as a new request and no
    information is shared. When loaded, each ASP.NET page goes through a regular page life cycle, from
    initialization and page load onward. When a user interacts with the page, causing the need for the
    server to process some control events, ASP.NET posts the values of the form to the same page for
    processing the event on the server. A new instance of the Web page class is created each time the page



                                                                                                        Page 29
1
/
    AX 2009 EP Dev Cookbook
    is requested from the server. When postback happens, ASP.NET uses the view state feature to preserve
    the state of the page and controls so that any changes made to the page during the round-trip are not
    lost. The Enterprise Portal framework leverages this feature, and Enterprise Portal ASP.NET controls
    automatically save their state to view state. The ASP.NET page reads the view state and reinstates the
    page and control state in its regular page life cycle. So you don’t’ need to write any code to manage the
    state if you’re using Enterprise Portal controls. But if you want to persist any in memory variables, you
    can write code to add or remove items from StateBag of ASP.NET.

    If you need to save the state of an X++ data set, you can use the pack and unpack design pattern to store
    the state, as shown here.

    public int Counter
    {
        get
          {
             Object counterObject = ViewState["Counter"];
             if (counterObject == null)
             {
                 return 0;
             }
            return (int)counterObject;
          }
        set
          {
             ViewState["Counter"] = value;
        }
    }

    The Enterprise Portal framework uses the EPStateStore table in Dynamics Ax to store the state of
    AxDataSourceControl. The states of all other controls are stored in the ASP.NET view state for added
    security. This storage is per user, and each user can read only his or her information. Writes and deletes
    are protected with AOS methods, and read is protected via code access permission.


    Access the Current Row / Field value
           private DataSetViewRow CurrentRow
           {
             get
             {
               try
               {
                 DataSetView dsv = this.CustomersDS.GetDataSet().DataSetViews["custTable"];
                 return (dsv == null) ? null : dsv.GetCurrent();
                 ...
           }

           priviate xxxx()
           {
             ...
             using (IAxaptaRecordAdapter custTable = this.CurrentRow.GetRecord())
             {
               customerName = custTable.GetField("Name").ToString();
             }
             ..




                                                                                                     Page 30
1
/
    AX 2009 EP Dev Cookbook
           }




    ExecuteQuery vs Research

    Try to use Research instead of ExecuteQuery if the recordset remains the same. (Query is not
    changed,no new or removed records. Only the records are updated )

    ExecuteQuery super() call executes the query generated by the init method and displays records.

    Research() Corresponds to re-activating executeQuery with the exception that research preserves the
    query’s filter, sorting and so on.

    If you want to refresh the form with records that were inserted or deleted in a method or job that was
    called, then you should use research.
    If you want to change the query to show other records, perhaps based on a modified filter, then you
    should use executeQuery.


    //setting the Action item context

        void webpart_ActionMenuItemClicked(object sender, ActionMenuItemEventArgs e)
        {
            //Check for Action menu item and refresh the datasource
            if (e.MenuItem.MenuItemAOTName == "HRMEPVirtualNetworkSkillDelete")

    dsVirtualNetworkSkill.GetDataSet().DataSetViews["HRMVirtualNetworkSkill"].ExecuteQuery
    ();
        }
    private void SetEmployeeIdOnDataSet(string emplId)
        {
            Microsoft.Dynamics.Framework.Data.Ax.DataSet ds =
    this.DS_TrvExpList.GetDataSet();
            ds.DataSetRun.AxaptaObjectAdapter.Call("setEmplId", emplId);
            this.DS_TrvExpList.GetDataSet().DataSetViews[0].ExecuteQuery();
        }


    if (e.MenuItem.MenuItemAOTName.ToLower() == STATUSCREATED)
                    {
                        ProjStatusUpd oStatusUpdate =
    ProjStatusUpd.construct(this.AxSession.AxaptaAdapter, this.CurrentRecord,
    ProjStatus.Created);
                        oStatusUpdate.run();

                            this.CurrentRow.DataSetView.Research();
                       }




                                                                                                   Page 31
1
/
    AX 2009 EP Dev Cookbook
    getfield vs. getfieldvalue
    GetField is on the AxaptaRecord which is a wrapper around the X++ instance of the record.
    GetFieldValue is on the DataSetViewRow which internally looks at the dbCache hooked to the X++
    record Please use GetFieldValue whenever you can because then your code will benefit from the perf
    improvements, the GetRecord is an implementation that is BC specific.


    Adding Javascript
    void webPart_SetMenuItemProperties(object sender, SetMenuItemPropertiesEventArgs e)
        {
            AxUrlMenuItem menuItem;
            string value = e.MenuItem.MenuItemAOTName.ToLower();
            // In process can go in any status
            // Set the properties
            switch (e.MenuItem.MenuItemAOTName.ToLower())
            {

                  case CASE_NEWLOG:
                      e.MenuItem.ClientOnClickScript = ShowCaseLogDialogJS;
                      break;

             }
        }

    public string ShowCaseLogDialogJS
        {
            get
            {
                StringBuilder text = new StringBuilder();
                text.Append("var size = DynamicsCommon.GetClientSize(); ");
                text.Append(" var screen = document.getElementById('" +
    this.screen.ClientID + "');");
                text.Append("screen.style.width = size[1]; ");
                text.Append("screen.style.height = size[0]; ");
                text.Append("screen.style.display = 'block'; ");
                text.Append("document.getElementById('" + this.caseLogBox.ClientID +
    "').style.display='block';");
                text.Append("document.getElementById('" + this.caseLogShadow.ClientID +
    "').style.display='block';");

                  return text.ToString();
             }
        }

    if (count > 1)
                {

                    // Open the confirmation box
                    ScriptManager.RegisterClientScriptBlock(this, this.GetType(),
    "openConfirmation", this.ShowDialogJS, true);
                }
                else
                {
                    this.CloseCaseWithGlobalObject();
                }




                                                                                                Page 32
1
/
    AX 2009 EP Dev Cookbook
    Action Web Menu Item
    Executing action web menu item through code

    AxActionMenuItem action = new AxActionMenuItem("SysFlushAOD");
            using (Proxy.Args args = new
    Proxy.Args(AxBaseWebPart.GetWebpart(this).Session.AxaptaAdapter))
            {
                args.parm = "Test1";
                action.Run(args);
            }



    Conditionally Making Grid Row Editable
    public partial class AxWebUserControl : System.Web.UI.UserControl
          {
           void Page_Init(object sender, EventArgs e)
           {
                  this.AxGridView1.SelectedIndexChanged += new
    EventHandler(AxGridView1_SelectedIndexChanged);
           }

           void AxGridView1_SelectedIndexChanged(object sender, EventArgs e)
           {
                  this.EnableGridEditing(this.IsCurrentAccountNumberEven());
           }

           private void EnableGridEditing(bool enable)
           {
                  if (enable)
                  {
                         this.AxGridView1.AllowEdit = true;
                         this.AxGridView1.EditIndex = this.AxGridView1.SelectedIndex;
                  }
                  else
                  {
                         this.AxGridView1.EditIndex = -1;
                         this.AxGridView1.AllowEdit = false;
                  }
           }

           private bool IsCurrentAccountNumberEven()
           {
                  DataSet dataSet = this.CustomersInfoDS.GetDataSet();
                  DataSetViewRow currentRow =
    dataSet.DataSetViews[this.AxGridView1.DataMember].GetCurrent();
                  if (currentRow != null)
                  {
                         string accountNumberStr =
    (string)currentRow.GetFieldValue("AccountNum");
                         if (!string.IsNullOrEmpty(accountNumberStr))
                         {
                                int accountNumber = Int32.Parse(accountNumberStr);

                                  return accountNumber % 2 == 0;
                          }
                  }

                  return false;




                                                                                     Page 33
1
/
    AX 2009 EP Dev Cookbook
            }
           }



    Workflow
    http://blogs.msdn.com/solutions/archive/2008/07/30/using-microsoft-dynamics-ax-2009-workflow-
    controls-in-ep.aspx


    Setting SharePoint Zone Width
    protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            //Add style to get 80/20 column widths for the left/right web part zones
            Microsoft.Dynamics.Framework.Portal.UI.StyleRegisterHelper.SetWebPartZoneWidth
    s(this.Page, Unit.Percentage(80), Unit.Percentage(20));
        }




    Enabling a toolbar menu item when a field is modified
    If AutoPostBack is enabled on the bound field in question and UpdateOnPostBack is enabled on the grid,
    then the RowUpdating and RowUpdated event will fire on the AxDataSourceView (the view the grid is
    bound to in the AxDataSource control) after the row is updated. You can write code in these events to
    enable/disable the toolbar menu item.


    Get the Bound field
    static AxBoundField GetField(DataControlFieldCollection fields, string name)
        {
            foreach (DataControlField field in fields)
            {
                AxBoundField boundField = field as AxBoundField;
                if (boundField != null && String.Compare(boundField.DataField, name, true)
    == 0)
                    return boundField;
            }
            return null;
        }
    AxBoundField parentCaseId = (AxBoundField)GetField(this.GeneralRight.Fields,
    "editParentCaseId**");



    Value Formatter
    If you’re not using data-bound controls and want your unbound ASP.NET controls to be formatted just
    like Enterprise Portal controls, you can leverage the AxValueFormatter class in the Enterprise Portal
    framework. This class implements ICustomFormatter and the IFormatProvider interface and defines a
    method that supports custom, user-defined formatting of an object’s value and provides a mechanism
    for retrieving an object to control formatting. For the various data types, specific ValueFormatter classes


                                                                                                     Page 34
1
/
    AX 2009 EP Dev Cookbook
    derived from AxValueFormatter are implemented: AxStringValueFormatter, AxDateValueFormatter,
    AxDateTimeValueFormatter, AxTimeValueFormatter, AxRealValueFormatter, AxNumberValueFormatter,
    AxGuidValueFormatter, and AxEnumValueFormatter.

    You use AxValueFormatterFactory to create AxValueFormatter objects. You can create any of the
    preceding formatters, or you can create a formatter based on an EDT in Dynamics AX. The data type for
    the extended data is retrieved from the metadata object for the EDT, and the culture information comes
    from the context

                private string ToEDTFormattedString(object data, string edtDataType)
                    {
                   ExtendedDataTypeMetadata edtType = MetadataCache.GetExtendedDataTypeMetadata(
                            this.AxSession,
                            ExtendedDataTypeMetadata.TypeNum(this.AxSession, edtDataType)
                        );
                        IAxContext context = AxContextHelper.FindIAxContext(this);
                        AxValueFormatter valueFormatter =
                AxValueFormatterFactory.CreateFormatter(this.AxSession, edtType, context.CultureInfo);
                        return valueFormatter.FormatValue(data);
                    }Validation




    Validators
    You use ASP.NET validator controls to validate user input on the server as well as (optionally) on the
    client (browser). The Enterprise Portal framework has ASP.NET validators specific to Dynamics AS:
    AxBaseValidator derives from BaseValidator, and AxValueFormatValidator derives from
    AxBaseValidator. Both are metadata-drive and are used intrinsically by bound fields, but you can also
    use them in unbound scenarios.

    ASP.NET validators are automatically validated when a postback that causes validation occurs. For
    example, an ASP.NET Button control causes validation on the client and the server when clicked. All
    validators registered on the page are validated. If any validator is found to be invalid, the page becomes
    invalid and Page.IsValid returns false.


    App Shared logic
        1. AXBaseUserControl.ascx
        2. App Common Controls - Enlistment:\source\Kernel\Web\Framework\App\CommonControls




    1. AXBaseUserControl
     method RequiresExternalContext:




                                                                                                         Page 35
1
/
    AX 2009 EP Dev Cookbook
        o  if your page has a grid with factbox for selected record, you should override this method so that
           the factbox is empty when the grid is
    2. The CommonControls DLL (namespace: Microsoft.Dynamics.Framework.Portal.CommonControls)
       contains some utility data and logic that could be used by user webcontrols without the need to
       duplicate code all over the places (since sharing code across user webcontrols is otherwise nearly
       impossible to do).
     class ControlHelper:
       o method CreateMenuItemWithTableContext:
            Creates a AxUrlMenuItem object using given data as table context (so that, eg, caller can
                access AxUrlMenuItem.Url.OriginalString used for ASP.NET HyperLink.)
            AxUrlMenuItem menuItem =
                ControlHelper.CreateMenuItemWithTableContext(CommonConst.TableName.C
                atExternalCatalog, CommonConst.FieldName.RecId,
                externalCatalogRecId, CommonConst. MenuItemName. CatProcurement);
        o method DecryptWKEY:
           Gets decrypted value keyed by the WKEY (which is normally the record id in context) from
              the querystring.
           This method saves caller the trouble of parsing the raw value.
      o method GetRowData:
           Gets data from the given datasource's current dataset view record.
           This method saves caller the trouble of going through the many steps of method calls to get
              value from datasource.
      o method GetCurrentSessionCompany:
           (Safely) gets the current session company in upper case.
           This method saves caller the try-catch and having to know how (which isn’t as trivial as it
              should be)
           Check out the many duplicated implementation of this very same logic in many existing user
              webcontrols, and you will appreciate this method (when you need it)
      o method ReplaceValueForKeyInUrl:
           Given urlString="http://www.abc.com/about.html?K1=V1&K2=V2", key="K1",
              oldValue="V1", newValue="Vxyz", returns
              "http://www.abc.com/about.html?K1=Vxyz&K2=V2".
     class CommonConst:
      o it has inner classes that define commonly-used constants such as table names, table field
          names, menuitem names.


    Correct a corrupt WebPage
    Suppose,: you made a change to a Webpart and now it won’t load anymore, add the following string to
    the querystring of the url : “?contents=1”




                                                                                                   Page 36
1
/
    AX 2009 EP Dev Cookbook
    Now the Webpart will be shown without being rendered. This allows you to change whatever necessary
    to its parameters.


    Get to the Enterprise Portal Library
    To get to the EP Doc library ( when you default page is throwing error) , type in the below url in the
    browser http:/<<epsiteurl>>/enterprise%20portal/forms/allitems.aspx


    Debugging
    If you are using mstsc make sure you are using /console switch.

    Debug X++ Code in EP
    http://msdn.microsoft.com/en-us/library/aa629010.aspx

    Debug C# in User Controls
    http://msdn.microsoft.com/en-us/library/cc567649.aspx

    Debug Framework Code
    1. Sync the portal files (cs) to your build

    2. gac the debug symbols from the depot (this will give you better visibility of code)

    3. load those symbols into VS and then attach w3wp.

    When attaching to the process, make sure you’re attaching to the process run by the BCProxy User.




                                                                                                      Page 37
1
/
    AX 2009 EP Dev Cookbook
    In order to set up your symbols, open “Tools->Options” in VS. In the resulting window, traverse to
    “Debugging-Symbols” and add references to PDB files.




    In order to attach to the C# code in Web Site projects, you’ll also need to enable debug mode.

         1) Navigate to the following directory:
            “C:\inetpub\wwroot\wss\VirtualDirectories\80”
            Note that ‘80’ is the default port number. You may be using a different port. If so, you’ll see it
            when navigating to the site (i.e. “http://machinename:18688...” is using port 18688).
         2) Open the ‘web.config’ file in VS.
         3) Find debug=”false” and change it to debug=”true”
         4) Refresh the page
         5) Remember to change this back when you are done




    64 bit machine deployment

         (1) If you are using 64 bit machine for EP, make sure getSharepointTemplatePath method of
             SysEPDeployment class in AOT has the below code . This is needed so that whenever you save
             user controls in VS, that will automatically be deployed to the EP server.

    public static str getSharepointTemplatePath()

    {

        xSession session = new xSession();



                                                                                                       Page 38
1
/
    AX 2009 EP Dev Cookbook
        int pointerSize = 0;

    ;

        pointerSize = System.IntPtr::get_Size();

        if (session.clientKind() != ClientType::Client && pointerSize != 4)

          return SysEPDeployment::getSharepointTemplatePathDotNet();



        return SysEPDeployment::getSharepointTemplatePathWin32();

    }

         (2) If you are making change to user controls in Visual studio, then there are no additional steps to
             have these changes propagated to the EP Server. Whenever you make changes on already
             existing user control in VS, it will automatically copy it to the SharePoint folder location. If you
             are creating new user control, when you add it to AOT by the right click menu and save the
             control in VS, it will automatically copy it to the SharePoint location.
         (3) If you are making changes to Tables/EDTs/Enums/Data Sets/Classes, then you need to click the
             “Refresh AOD” link available to the administrators in the EP home site quick launch. This will
             clear the metadata cache. You can also do an “iisreset” if needed
         (4) If you are making change to proxy file/static files/resources, then you need to deploy them. User
             AxUpdatePortal utility http://msdn.microsoft.com/en-us/library/dd261467.aspx (Manage
             Deployment Option does not work in 64 bit machines,so you have to use AXUpdatePortal)


    Change History

    Updated Date                           Updated By                          Comments
    01/05/10                               Meysun                             Initial Creation




                                                                                                       Page 39
1
/

				
DOCUMENT INFO
Shared By:
Categories:
Tags:
Stats:
views:20
posted:11/5/2011
language:English
pages:39