Welcome to MSDN Blogs Sign in | Join | Help

64bit machine - VS EP add-in not deploying user control to SharePoint while saving

In 32 bit machine, when you edit an user control in VS using EP add-it, it automatically uploads the saved file to both AOT and to SharePoint (“%SYSTEM Drive:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\TEMPLATE\LAYOUTS\ep" folder on the web server)

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 same as in 32 bit env.

        public static str getSharepointTemplatePath()
        {
           str templatePath ='';
           ;
           templatePath =SysEPDeployment::getSharepointTemplatePathDotNet();
           return templatePath? templatePath:SysEPDeployment::getSharepointTemplatePathWin32();
       

 

Thanks to John Hermsen from Giant Bicycles for providing a similar workaround.

(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

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)

Posted by meysun | 1 Comments
Filed under:

AX 2009 EP Development CookBook

I have posted the EP Development CookBook at http://blogs.msdn.com/epblog/archive/2010/01/05/ax-2009-ep-development-cookbook.aspx.

This consolidates all the various blog posts into one stop development guide.

Posted by meysun | 0 Comments

EP Tips-n-Tricks - Data Sets / Data Sources

Happy New Year !!!

 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

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

    }
}

 

Data Sources

Set the below properties at the individual datasources.

InsertAtEnd : No

InsertIfEmpty : No

 

Also set Allow* properties on the Data source appropriately.

Init

Adding ranges

 

public void init()

{

    super();

 

    qbrName = this.query().dataSourceTable(tablenum(InventDimCombination)).addRange(fieldnum(InventDimCombination,Name));

    qbrName.status(RangeStatus::Hidden);

 

    qbrItem = this.query().dataSourceTable(tablenum(InventDimCombination)).addRange(fieldnum(InventDimCombination,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

    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;

 

    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();

}

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.

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;

        }

    }

8.       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;

            }

        }

    }

 

9.       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;

    }

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;

    }

 

Posted by meysun | 0 Comments
Filed under:

UpdateOnPostBack property of AXForm

If you need to read the values that the user entered in a text box before the record is committed to filter the possible values for the second text box then first you should set the autopostback property of the AxBoundField to true. Also you need to set the UpdateonPostback property of the AXForm.

UpdateonPostback property is set if the record cursor needs to be updated when post back happens, so that other controls could read the change. You could then use the row.GetFieldValue("FieldName") to get the value that that user entered in the text box.

Posted by meysun | 4 Comments
Filed under:

Add all Role Centers to AX Client Favorites for demo purpose

Run this job in AX Client to add all oob role centers to your favorites section in AX Client for easy demo purpose. 

static void AddRoleCentersToFavorite(Args _args)
{
str sDefault ="Default";
SysProfiles uprofile;
MenuFunction mf;
TreeNode treeNode;
    TreeNodeIterator iterator;
    TreeNode newTreeNode;
    UserMenuList userMenu;
    Menu menuNode;
    #AOT
;

 treeNode = infolog.userNode();
    iterator = treeNode.AOTiterator();
    treeNode = iterator.next();
    if (treeNode)
    {
        userMenu = treeNode;

        // find 'My Favorites' user menu; if not found, create one
        treeNode = userMenu.AOTfindChild("@SYS95713");
        if (!treeNode)
        {
            userMenu.createMenu("@SYS95713");
            treeNode = userMenu.AOTfindChild("@SYS95713");
        }
        menuNode = treeNode;

while select ProfileId from uprofile
{

mf = new MenuFunction("DemoRoleCenter"+uprofile.ProfileId,MenuItemType::Action);
mf.AOTsetProperty("Label",uprofile.ProfileId);
mf.AOTsetProperty("ObjectType","Class");
mf.AOTsetProperty("Object","SwitchRoleCenter");
mf.AOTsetProperty("Parameters",uprofile.ProfileId);

mf.AOTsave();
menuNode.addMenuitem(mf);
menuNode.save();
}

mf = new MenuFunction("DemoRoleCenter"+sDefault,MenuItemType::Action);
mf.AOTsetProperty("Label",sDefault);
mf.AOTsetProperty("ObjectType","Class");
mf.AOTsetProperty("Object","SwitchRoleCenter");
mf.AOTsetProperty("Parameters",sDefault);

mf.AOTsave();
menuNode.addMenuitem(mf);
menuNode.save();


        infolog.navPane().refreshFavorites("@SYS95713");

    }
}

Posted by meysun | 3 Comments
Filed under:

How to set focus on the asp.net textbox in AxPopup form?

To set the focus include this method in your page that is opened in the popup window and call the method without control name in the page load event.

For example to set the focus on txtCustAccount

 

protected void Page_Load(object sender, EventArgs e)

    {

       

        SetFocus(txtCustAccount);

    }

 

public static void SetFocus(Control control)

    {

        StringBuilder sb = new StringBuilder();

 

        sb.Append("<script language='JavaScript'>");

        sb.Append("function SetFocus(){document.");

 

        Control p = control.Parent;

        while (!(p is System.Web.UI.HtmlControls.HtmlForm)) p = p.Parent;

 

        sb.Append(p.ClientID);

        sb.Append("['");

        sb.Append(control.UniqueID);

        sb.Append("'].focus();}");

       

        sb.Append("window.onload = SetFocus;</script>\r\n");

 

        control.Page.RegisterClientScriptBlock("SetFocus", sb.ToString());

    }

Posted by meysun | 0 Comments
Filed under:

AxPopup Controls in EP

AxPopup Controls

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.

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)

            {

                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))

            {

                //Displaying error message: Account number is not specified

                DisplayInfolog(InfoType.Error, "@SYS24085");

                return;

            }

 

            //Validating the Customer Account no. entered

            if (!ApplicationProxy.SmmOpportunityStatusUpdate.checkCustomerAccount(this.AxSession.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;

            }

        }

    }

 

Posted by meysun | 1 Comments
Filed under:

Redirecting in EP user control to download a file

If you have a webpage to generate files such as word doc or pdf and you need to invoke them in a button click event of  an user control used in EP and allow the user to download the file through the browser. generally you would think of calling response.redirect function. This function  redirects to the download page and since it sets the mime type as the respective file, it prompts the user to save the file to the local machine or open it using the right application. Since AX usercontrols inherently  uses AJAX postbacks, the postback progressbar will continue to display "Loading Information" even after the file is downloaded when response.redirect is used. This is because response.redirect supposed to replace the current page displayed in the browser, but in this case it actually streams file and does not replace the currently rendered page in the browser. For such scenarios, instead of using response.redirect, you could execute a client side javascript to push the generated file in a new browser window and avoid the above issue.
 
protected void Button1_Click(object sender, EventArgs e)
    {
        AxUrlMenuItem menuItem = new AxUrlMenuItem("EPDocuGet");
        DataSetViewRow row = dsEPCustInvoiceJournalInfo.GetDataSet().DataSetViews[0].GetCurrent();
        AxTableContext context = AxTableContext.Create(row.GetDefaultTableDataKey(row.DataSetView.Metadata.RootDataSource));
        menuItem.MenuItemContext = context;
  
        //Response.Redirect(menuItem.Url.ToString());
 
        string downloadURL = "window.open('" + menuItem.Url.ToString() + "', '_blank', '' );";
        ScriptManager.RegisterStartupScript(this, typeof(string), "OPEN_WINDOW", downloadURL, true);
 
 
    }
 
Posted by meysun | 1 Comments
Filed under:

Persisting Filter conditions in EP Grid

Persisting Filter condition in EP Grid

In AX 2009, EP grid control comes with an advanced filter. Here is a code to persist the filter condition the user last entered in a page for that user, so that later when the user comes back to the same page the last filter is applied and user didn’t have to reenter then.

This code sample assumes a dataset with the name “EPSalesTableList” which contains the datasource “SalesTable”

 (1) First override the pack method of the dataset ( EPSalesTableList in this example) in AOT

public container pack()
{

container ret;
SysLastValue sysLastValue;

formdatasource filterDataSource;
;

filterDataSource = SalesTable_ds; // Put your datasource name

    ttsbegin;
       // Delete last saved query for the current dataset
    delete_from sysLastValue
        where sysLastValue.Company      == curext()
           && sysLastValue.UserId       == curuserid()
           && sysLastValue.RecordType   == UtilElementType::DataSet
           && sysLastValue.ElementName  == filterDataSource.name()
           && sysLastValue.DesignName   == filterDataSource.name();

    // If there is a new queryRun() object then serialize and save it
    // in the sys last value table
    // Put your datasource name
   
    if (filterDataSource.queryRun())
   {
   
        sysLastValue.RecId = 0;
        sysLastValue.Company      = curext();
        sysLastValue.UserId       = curuserid();
        sysLastValue.RecordType   = UtilElementType::DataSet;
        sysLastValue.ElementName  = filterDataSource.name();
        sysLastValue.DesignName   = filterDataSource.name();
        sysLastValue.value = SysQuery::packRangeAndSortorder(filterDataSource.queryRun().query());   
        sysLastValue.insert();
    }
    ttscommit;

 

    ret = super();

 

 

    return ret;

}

 

 

(2) Second override the init method of the datasource ( SalesTable in this example) within that dataset in AOT

public void init()
{
SysLastValue    sysLastValue;
    Query savedQuery;
    ;
    super();

// get the last value from the  sys last value table
    select firstonly sysLastValue
        where sysLastValue.Company      == curext()
           && sysLastValue.UserId       == curuserid()
           && sysLastValue.RecordType   == UtilElementType::DataSet
           && sysLastValue.ElementName  == this.name()
           && sysLastValue.DesignName   == this.name();

    if (sysLastValue && sysLastValue.Value)
    {
              // If there is an unpack error delete the saved query

       if (!SysQuery::unpackRangeAndSortorder(this.query(), sysLastValue.value))
        {

            ttsbegin;
            delete_from sysLastValue
                where sysLastValue.Company      == curext()
                   && sysLastValue.UserId       == curuserid()
                   && sysLastValue.RecordType   == UtilElementType::DataSet
                   && sysLastValue.ElementName  == this.name()
                   && sysLastValue.DesignName   == this.name();
            ttscommit;
        }

    }
               

 

 Make sure you replace the datasourcename variable filterDataSource in the pack method with your datasource name.Save the changes, refresh AOD and now go to the page that is using this dataset and enter some filter condition & apply. Close the browser and reopen the page. Now you should see that the filter that you last applied before the browser was closed is still applied in this page.

Arif Kureshy, who is the dev manager for EP came out with this code snippet. So thanks to him for providing this sample code.

 

Posted by meysun | 3 Comments
Filed under:

X++ based Web User Interface is discontinued in the next version of Microsoft Dynamics AX Enterprise Portal

During AX 2009, we introduced ASP.net based EP framework which brings in tons of value such AJAX out of the box, rich and responsive controls, power of .net etc. We kept the old X++ Web framework in the product for one release to help the partners and customers migrate to the new framework. Now we have published the discontinuation notice in customer source / partner source. In the next version of AX, only asp.net based web user interface will be shipped.

 https://mbs.microsoft.com/partnersource/newsevents/news/newsgeneral/ax_epuiframework.htm  

 https://mbs.microsoft.com/customersource/newsevents/news/generalnews/ax_epuiframework.htm    

 

Posted by meysun | 0 Comments
Filed under:

Screencast - How to set up Enterprise Portal (EP) in a Network Load Balancing (NLB) MOSS 2007 cluster

Anunay Kumar from the Enterprise Portal test team created a step-by-step guide on setting up SharePoint in NLB http://blogs.msdn.com/epblog/attachment/9727309.ashx and the screencast on setting up EP on such NLB web farm http://msdn.microsoft.com/en-us/dynamics/ax/ee384254.aspx. This screencast and more videos are available at "How do I" Videos - Dynamics AX section.

Thanks Anunay and we are excited to see that EP team members continue to add more content, videos and samples about Microsoft Dynamics AX 2009 EP.

Next we are targeting to create a similar Screencast about Perimeter setup / External facing Web site setup.

Posted by meysun | 2 Comments
Filed under:

Enterprise portal application functionality overview document

Jim Brotherton created this very useful document that describes the modules, features and business tasks that user perform in Enterprise Portal http://www.microsoft.com/downloads/details.aspx?FamilyID=0a0abfc4-964f-43ee-ad26-3d5d4c156269&displaylang=en. We have produced lots of good documentation for EP in AX 2009 and continue to look for ways to adding even more. If you have suggestions, please post a comment to this blog post with the topic name.

 

Posted by meysun | 0 Comments

Record Context

Steve Kubis from the UA team recented added the topic about Context in Enterprise Portal. It's talks about common context scenraios http://msdn.microsoft.com/en-us/library/ee330228.aspx and how the framework enables this without any code and an advanced topic on how to use it in code http://msdn.microsoft.com/en-us/library/ee330227.aspx. Thanks Steve
Posted by meysun | 0 Comments
Filed under:

Custom Bound Fields in FieldGroup

You could make the AxBoundFieldGroup use the CustomBoundField (http://blogs.msdn.com/solutions/archive/2009/04/20/ax-custom-bound-fields.aspx) instead of the regular bound field by hooking into the OnCreatingBoundField event (KB971547) of the  AxBoundFieldFactory.

 For example create an assembly with the below code and put it in GAC.

public class AxSampleBoundFieldFactory
{
 public
void OnCreatingBoundField(object sender, CreatingBoundFieldEventArgs eventArgs)
 {
   if (eventArgs.Field.Name == "Date")
     eventArgs.BoundField =
new AxSampleDateBoundField();
 }
}

Then modify the master page (C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES\DynamicsAxEnterprisePortal\defaultax.master) and add the below code to invoke this eventhandler in page init. Now any page that displays a fieldgroup will use the AxSampleDateBoundField for any field with the name "Date". You can add any logic that you want here for example you may want to use other field meta data properties instead of the name.


  private AxSampleBoundFieldFactory customBoundFieldFactory;
   
    protected override void OnInit(EventArgs e)
    {
        base.OnInit(e);

        // Subscribe to the bound field factory event
        this.customBoundFieldFactory = new AxSampleBoundFieldFactory();
        AxBoundFieldFactory.Instance.CreatingBoundField += this.customBoundFieldFactory.OnCreatingBoundField;
    }

    protected override void OnUnload(EventArgs e)
    {
        // Unsubscribe to the bound field factory event
        AxBoundFieldFactory.Instance.CreatingBoundField -= this.customBoundFieldFactory.OnCreatingBoundField;       
       
        base.OnUnload(e);
    }

Posted by meysun | 1 Comments
Filed under:

Inside Microsoft Dynamics AX 2009 book RTM'ed

Inside Microsoft Dynamics AX 2009 book RTM'ed

http://blogs.msdn.com/microsoft_press/archive/2009/05/20/rtm-d-today-inside-microsoft-dynamics-ax-2009.aspx

I wrote two chapters in Inside Dynamics AX 2009 book about Enterprise Portal and Role Centers. I also contributed to the Architecture Chapter and upgrade. Thanks to the entire EP team who implemented these great features and contributed in many ways to the content of these chapters. These chapters have wealth of info for developers and I would recommend strongly for EP / Role Center developers :) :) .

 

Posted by meysun | 5 Comments
Filed under: ,
More Posts Next page »
 
Page view tracker