Documente Academic
Documente Profesional
Documente Cultură
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
Page 2
Page 3
Page 4
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; }
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 1
Page 5
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
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(); }
Page 7
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
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
<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
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 Roleproperty 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
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.
protectedvoid Page_Init(object sender, EventArgs e) { this.SetupMode(); } privatevoid 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
Page 12
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); } } }
Page 13
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. TheRootTableContext property returns the TableContext of the root table in that dataset 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 { get { AxBaseWebPart webpart = AxBaseWebPart.GetWebpart(this);
Page 14
Sample code for getting the record from the connected Web partfollows.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"); } } }
Page 15
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 )
using Microsoft.Dynamics.Framework.Portal.UI;
Page 16
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
protectedvoid 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
<div> <br/> <br/> <tablestyle="width: 100%"> <tr> <tdclass="PopoverFormText"> <asp:LabelID="lblCustAccount"runat="server"Text="<%$ axlabel:@SYS7149 %>"></asp:Label> </td> <tdclass="PopoverFormText"> <asp:TextBoxID="txtCustAccount"runat="server"MaxLength="20"></asp:TextBox> <dynamics:AxPopupChildControlID="popupChild"runat="server"> <dynamics:AxPopupFieldname="hiddenCustomerAccountNo"TargetControlId="txtCustA ccount"/> </dynamics:AxPopupChildControl> </td> </tr> <tr><tdcolspan="3"><br/><hrclass="hr"/> </td></tr> <tr> <tdalign="right"colspan="2"> <asp:Buttonid="OkButton"CssClass="okCancelButton"runat="server"Text="<%$ axlabel:@SYS5473 %>"onclick="OkButton_Click"/> <inputid="CancelButton"class="okCancelButton"runat="server"type="button"value ="<%$ axlabel:@SYS50163 %>"onclick="window.close();"/> </td> <tdstyle="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. protectedvoid OkButton_Click(object sender, EventArgs e) { try { if (this.txtCustAccount.Text.Equals(string.Empty)) {
Page 19
privatevoid GetData() { DataSourceViewSelectCallback callback = newDataSourceViewSelectCallback(PrintData); AxDataSource1.GetDataSourceView("CustTable").Select(DataSourceSelectArgu ments.Empty,callback); } privatevoidPrintData(IEnumerable data) { IEnumerator i = data.GetEnumerator(); while (i.MoveNext())
Page 20
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" DataSet="DemoSet" DataSetView="Table1" TargetControlId="TextBox1" Visible="<%$ AxDataSet:DemoSet.Table1.AccountNum.AllowEdit %>">
Page 21
Code Behind to hide the lookup control conditionally and disable the cell protectedvoid 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
Page 23
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
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); }
Page 25
Custom Lookup
Managed Code Custom Lookup
protectedvoid 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 nameLookup.LookupDataSet = new DataSet(this.AxSession, sysDataSetBuilder.toDataSet());
Page 26
Page 27
There are four properties that control the Page Title: y y y y 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 cant 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
y y
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. } }
View State
The Web is stateless,which meansthat 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, causingthe 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 is
Page 29
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.
Page 30
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.
Page 31
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
Page 33
Workflow
http://blogs.msdn.com/solutions/archive/2008/07/30/using-microsoft-dynamics-ax-2009-workflowcontrols-in-ep.aspx
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 andthe 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
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 Buttoncontrol 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.
Page 35
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. o
Page 36
Debugging
If you are using mstsc make sure you are using /console switch.
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
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
Page 38
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 utilityhttp://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 01/05/10 Updated By Meysun Comments Initial Creation
Page 39