Wednesday, May 28, 2014

DMF – Stack Trace error @ \Tables\DMFEntity\generateXML_WPF


It appears that whenever you go to Company/Data import export framework/Setup/Target Entities and then click on an entity then “Modify target mapping” you may get a stack trace error that is linked to \Tables\DMFEntity\generateXML_WPF and it will not allow you to open up this window for the specific entity but it will for others. To fix the error you should first try the following:

 

1.       Open \Tables\DMFEntity\generateXML_WPF and the issue is between line 201-208.

a.      What happens is the SysDictField object is called but if the table no longer contains the field in the mapping then it generates a “null” instance of SysDictField which is called on line 204 which causes an error to be thrown.

2.       We need to modify the code base for DMF so it can handle null objects and let us know where the issue is

3.       The following from line 196-209 should be changed:

Orignal:

// Generate Target Fields

    while select Entity, XMLField, TargetTable, TargetField from targetFields
        where targetFields.Entity   == _entity.EntityName  &&
              targetFields.XMLField != #blank
    {
        dictField = new SysDictField(tableName2id(targetFields.TargetTable),fieldName2id(tableName2id(targetFields.TargetTable),targetFields.TargetField));
        xmlElement = xmlDocument.createElement(#column); //Column
        xmlElement.setAttribute(#name, targetFields.XMLField); //Name
        xmlElement.setAttribute(#type, enum2str(dictField.baseType())); //Type
        xmlElement.setAttribute(#isActive,  enum2str(boolean::true));
        xmlElement = childNode.appendChild(xmlElement);
        xmlElement.setAttribute(#Label, dictField.label());
        xmlElement.setAttribute(#Help, dictField.help());
    }

 

New Code:

  // Generate Target Fields
    while select Entity, XMLField, TargetTable, TargetField from targetFields
        where targetFields.Entity   == _entity.EntityName  &&
              targetFields.XMLField != #blank
    {
        dictField = new SysDictField(tableName2id(targetFields.TargetTable),fieldName2id(tableName2id(targetFields.TargetTable),targetFields.TargetField));
       // check to see if the dictField is null, if it isn’t then we can handle the field but if it is then we need to alert the user of the table and field that should be removed from the mapping
if(dictField != null)
        {
            xmlElement = xmlDocument.createElement(#column); //Column
            xmlElement.setAttribute(#name, targetFields.XMLField); //Name
            xmlElement.setAttribute(#type, enum2str(dictField.baseType())); //Type
            xmlElement.setAttribute(#isActive,  enum2str(boolean::true));
            xmlElement = childNode.appendChild(xmlElement);
            xmlElement.setAttribute(#Label, dictField.label());
            xmlElement.setAttribute(#Help, dictField.help());
        }
        else
        {
                // alert the user of the bad mapping
info("error-table: " + targetFields.TargetTable + "  field: " + targetFields.TargetField);
        }
    }

 

 

4.       Once you add this bit of code you should compile the table and rerun the target mapping. This time the window should open but will give you am info box of the bad field.

5.       Once you have this field we now need to remove the field from the mapping. However sometimes it does not exists within the visual mapping so we need manually remove it via the following

 

static void FixEmerysDMFProductIssues(Args _args)

{

    DMFTargetXML dmftargetxml;

    delete_from dmftargetxml

    where dmftargetxml.targettable == '<table name from step 3 in info box>' && dmftargetxml.targetfield == '<field name from step 3 in info box>';

}

 

6.       Whenever you open the target mapping windows for the specific entity you should no longer get the error or a msg with a table/field info that we defined in step 3.

Wednesday, May 21, 2014

server 2012 not being able to load custom dll/reference .dll compile issues on AOS

So I ran into this issues a while back and I figured I would share how I fixed it.


So we are using a custom WYSIWYG WinForm editor (C#/.NET 4.0/Targeted for x86/x64) control inside of AX. However I noticed that whenever I went to do a compile locally  or tried to even open the form on the AOS it would always get an error and tell me that it couldn't find the reference. Even though it was in all of the .dll folders (manually bin folder copy and dynamic auto deploy temp folder)

What I figured out was all of the local and terminal server clients had Visual Studio installed on it. So I tried installing Visual Studio 2010 on the AOS server itself. Once that it done then you can compile your objects that reference outside .dll's and open the form successfully

I'm not too sure why this fixes the issues, my guess is its one of the many runtime packages that gets installed with Visual Studio fixes the issue.

Would anyone else know why this fixes it?

But if you want a quick fix just install Visual Studio and all of the compile reference issues should go away.

Sub Reports within AX SSRS Reports

​So while trying to add a subreport (no parms) to an existing report I discovered some goofy things that need to be followed in order for a sub report to work within AX.



1. Put both reports within the same project (model project within Visual studio)

2. Right Click on the sub report and choose properties. You have to manually type in the report name you want to use instead of being given a dropdown like normal SSRS

3. Include the design name (ReportName.Report, ReportName.PrecisionDesign1, etc...) within the report name mentioned in step 2.

4. Deploy the report to the same folder on the SSRS server (you may need to "move" your report into StaticReports> language> folder)



5. Previewing of subreports does not work within visual studio for AX sub reports. Once you follow steps 1-4 you should be able to add the model to the AOS. Then deploy your modified report and the subreport should show up correctly whenever you call the report from AX.





I sure do hope microsoft has some big enhancements for SSRS in 2015.

Tuesday, May 20, 2014

looping through a forms datasource

This will show you how to look through all of the records of a forms data source or just the selected records without affecting what is populated within the data source



How to loop through all records of a datasource with the name of InventTrans



InventTrans                 localInventTrans = InventTrans_DS.getFirst() as InventTrans;
ItemId                      itemId;

while(localInventTrans)
{
  //access fields by using localInventTrans.fieldname
  itemId = localInventTrans.ItemId;


  //get the next record from the datasource
        localInventTrans = InventTrans_DS.getNext() as InventTrans;
}

 
How to loop through ONLY the selected records of a datasource with the name of InventTrans. This could be used if you have a grid and want the user to select only certain records then pass those records to a class, form, method, etc...


InventTrans                 localInventTrans;
ItemId                         itemId;

//get the first selected record of the datasource and loop through all of the selected records
for(localInventTrans = InventTrans_DS.getFirst(true) ? InventTrans_DS.getFirst(true) : InventTrans_DS.cursor(); localInventTrans; localInventTrans = InventTrans_DS.getNext())
{
                   itemId = localInventTrans.ItemId;
                   info(itemId);
}




Friday, May 16, 2014

Get users screen resolution

Get users screen resolution
int screenWidth, screenHeight;
#WinAPI
//get the user resolution
screenWidth = WinAPI::getSystemMetrics(#SM_CXSCREEN);
screenHeight = WinAPI::getSystemMetrics(#SM_CYSCREEN);


Create .csv file from data

    The following code shows how to create a csv file



    CommaIo file;
    container line;

    TableName table;

    FileIoPermission perm;

    #define.ExampleFile(@"c:\test\filename.csv")

    #File




    perm = new FileIoPermission(#ExampleFile, #io_write);

    perm.assert();







    file = new CommaIo(#ExampleFile, #io_write);

    file.outFieldDelimiter(',');// for semicolon separator




    if (!file || file.status() != IO_Status::Ok)

    {

        throw error("File cannot be opened.");

    }

    while select spools

    {

        line = [table.fieldName1, table.fieldName2, table.fieldName3, variable];

        file.writeExp(line);

    }




    CodeAccessPermission::revertAssert();​

Basic lookups and referenced field lookups

In the dynamics ax 2012, there are different ways to fill the combo box/drop down list


How to create a simple lookup


The SysTableLookup class is provided by the standard application to allow programmers to easily create their own lookup forms, in code.
The basic steps to using this class are as follows:

  1. Create the sysTableLookup object
  2. Create the query to select the lookup data
  3. Add  the fields shown on the lookup
  4. Performs the lookup


client static void lookup<TableName> (FormStringControl _ctrl)
{
    SysTableLookup          sysTableLookup       =  SysTableLookup::newParameters(tableNum(<tableName>),_ctrl);
    Query                   query                = new Query();

    // create the query for the lookup
    QueryBuildDataSource    queryBuildDataSource = query.addDataSource(tableNum(<tableName>));

    // Add fields that will be shown in the lookup as columns        
    sysTableLookup.addLookupfield(fieldNum(<tableName>,<FeildName1>));
    sysTableLookup.addLookupfield(fieldNum(<tableName>,<FeildName2>));

    //Add the query to the lookup form
    sysTableLookup.parmQuery(query);

    // Perform the lookup
    sysTableLookup.performFormLookup();
}




How to create a simple lookup Reference
 

 The SysReferenceTableLookup class is used to construct lookup forms for reference controls.

  1. Create the SysReferenceTableLookup object
  2. Create the query which will be used to select the lookup data
  3. Add the fields which will be shown on the lookup
  4. Perform the lookup 
This method is now the standard method used to lookup the data for drop down when there is any modification needed to override the behavior of the functionality provided by the automatic lookup




public static client <tableName> lookup<tableName>(
    FormReferenceControl        _formReferenceControl)
{
    Query                   query;
    SysReferenceTableLookup referenceLookup;

    if (_formReferenceControl == null)
    {
        throw error(Error::missingParameter(null));
    }

    referenceLookup = SysReferenceTableLookup::newParameters(
        tableNum(<tableName>),
        _formReferenceControl,
        true);

    // create the query for the lookup form
     query.addDataSource(tableNum(<tableName>));

    // Add fields that will be shown in the lookup form as columns
    referenceLookup.addLookupfield(fieldNum(<tableName>,<FeildName1>));
    referenceLookup.addLookupfield(fieldNum(<tableName>,<FeildName2>));


    // Add the query to the lookup form
    referenceLookup.parmQuery(query);

    // Perform the lookup and return the selected record
    return referenceLookup.performFormLookup() as <tableName>;
}

Using WCF to enable spellcheck on a textbox in 3 steps

This post will show you how to enable spell check on a textbox within a form using built-in WCF controls.

1. Right Click on form design node within the AOT and add the control "ManagedHosts"
2. Select PresentationFramework and then the Textbox control.
3. On the forms init method type the following

public void init()
{
         System.Windows.Controls.TextBox textBox         

          super();

          textBox = TextBoxManagedHost.control();
          Systsem.Windows.Controls.SpellCheck::SetIsEnabled(textBox, true);

}



SpellCheck will now be enabled on the text box control you added and after hitting the space bar if a word is misspelled you will see a red underline and the ability to right click on the word and see a suggested spelling.

Note: because this is a managed host control you can not tie it to a datasource and will need to write code to pass in the value and save it.

Refresh the calling form

/// <summary>
/// Refresh the caller form by calling the research(true) which does not work. 
/// research(True) alone will jump the cursor to the begining (either first or last) record.
/// </summary>
/// <remarks>
/// Taken from form InventTableInventoryDimensionGroups.closeOk()
/// </remarks>
public void refreshCaller()
{
    Common          common;
    FormDataSource  callingFormDataSource;      
   
    common = element.args().record();
    if (common)
    {
        callingFormDataSource = common.dataSource();
        if (callingFormDataSource)
        {
            // Referenced datasources must be reread before calling research as data has been modified behind the scenes
            // without calling research will fail to position selection correctly
            callingFormDataSource.reread();      
            callingFormDataSource.rereadReferenceDataSources();           
            callingFormDataSource.research(true);
        }
    }
}

Get paper trays available on network printer

(this is a job)

static void PrinterTest(Args _args)
{
    System.Drawing.Printing.PrintDocument printDocument = new System.Drawing.Printing.PrintDocument();
    System.Drawing.Printing.PrinterSettings printSettings = new System.Drawing.Printing.PrinterSettings();
    System.Drawing.Printing.PaperSource[] printSource;
    System.Drawing.Printing.PaperSource printSourceMain;
    System.Exception printException;
    int trayCount, totalCount;
    int rawId;
    str trayName;
   
    try
    {
        new InteropPermission(InteropKind::ClrInterop).assert();
        //set which printer we need to query
        printSettings.set_PrinterName(@"\\server\networkprintersharename");
        printDocument.set_PrinterSettings(printSettings);
        //load in all of the current trays(paper sources_ for the printer and get the count
        printSource = printSettings.get_PaperSources();
        totalCount = printSource.get_Count();
        //loop through all of the trays but make sure the raw kindid is less than 1000 to get valid trays that we can print to
        for(trayCount = 0; trayCount < totalCount; ++trayCount)
        {
            printSourceMain = new System.Drawing.Printing.PaperSource();
            //get the current tray
            printSourceMain = printSource.get_Item(trayCount);
            //get the trays raw kind id
            rawId = printSourceMain.get_RawKind();
            //check to see if the tray is a custom object or something we can print to
            if(rawId < 1000)
            {
                //get the trays name
                trayName = printSourceMain.get_SourceName();
                info(trayName);  
            }
        }
    }
    catch
    {
        printException = CLRInterop::getLastException();
        info(printException.ToString());
    }
}


HOW TO: Creating a new role center in 10 steps

A step by step guide on how to create a new role center

1. On the Home page of the EPDefaultRoleCenter , Go to Site Actions > More options as can be seen in the above screen shot.

2. From the next screen select the Web Part Page template and click on the Create button.

3. On the next step give the name for your role center page , pick a layout template and set the document library drop down to Enterprise Portal then hit the Create button.

4. Customize the role center with the layout and webparts you like

5. In the AOT under the Web node go to Web Menu Items > URLs Right click and select New URL option.

6. Now , set the properties for the newly created URL

  •   Specify the Name for the URL. Use a name that specifies the page that the URL will point to.
  •   Specify a label for the page.
  •   Specify the URL, with the following form: Enterprise%20Portal/PageName.aspx 
   
 7. Set the Home Page property to Yes.

 8. Fill the Page Definition property by giving the desired page definition name.

 9. Save the new URL Web Menu Item and  Right Click on the newly created URL and select the Import page option as shown above.


10. Now go to System administration > Common > User Profiles.
On the User Profiles form click on the New button.
Fill the Profile ID  , Description and Paste the Name of your URL Web Menu Item  and hit the Close button on this form.
 
 
You can now  view your role center in the browser by clicking on the View role center button on the User Profiles form .