July, 2010

  • Microsoft Dynamics NAV Team Blog

    Let NAV Speak (with a Simple and Useful Client Add-in)

    • 8 Comments

    In this blog you will find the source code (below) to “let NAV speak.” You would have a wide range of possibilities to use this simple Add-in and enlarge this project.

    If you want to know more about Client Add-ins you can refer to this MSDN link:

    Extending the RoleTailored Client Using Control Add-ins and Microsoft Dynamics NAV 2009 SP1

    This simple Client Add-In is based on System.Speech namespace:

    Microsoft.Speech.Synthesis Namespace

    Step by step creation of the NSpeech Add-In

    (Remember the ‘DodgeBall’ rules: Develop, Sign, Place, Register and Develop)

    1. DEVELOP your add-in (in Visual Studio)
    2. Strong SIGN and build
    3. PLACE DLLs into Add-ins folder
    4. REGISTER the add-in in Table 2000000069, Client Add-in
    5. DEVELOP your C/AL code (in Object Designer)

    A. Create a New Class Project

    1. Open Visual Studio (in this example I am using Visual Studio 2010)
    2. Create a New Project (CTRL+SHIFT+N) with these parameters
      • Visual C# – Windows
      • Class library
      • .NET Framework 3.5
      • Name: NSpeech
      • Location: C:\TMP (or whatever location you like)
      • Solution Name: NSpeech
      • Create directory for solution

    NSpeechVS

    B. Create a Strong Name Key (SNK)

    1. Go to Project > Properties (NSpeech Properties…)
    2. From the Project Properties form go to the Signing tab
    3. Tick the Sign the assembly option
    4. Create a New SNK (e.g. TestSpeechNav.snk)

    NSpeechSign

    C. Add References to the Project

    1. Click on the Class1.cs tab (return to the project)
    2. In the Solution Explorer window select Reference, right Click, Add Reference
    3. Add reference to
      • Microsoft.Dynamics.Framework.UI.Extensibility (Version 1.3.0.0) (By default, the path to the assembly is C:\Program Files\Microsoft Dynamics NAV\60\RoleTailored Client)
      • System.Drawing (Version 2.0.0.0)
      • System.Speech (Version 3.0.0.0)
      • System.Windows.Forms (Version 2.0.0.0)

    NSpeechRef

    D. Develop your NSpeech Project

    (You can simply copy and paste this code into your Class project.)

    using System;

    using System.Collections.Generic;

    using System.Text;

    using System.ComponentModel;

    //Add a reference to the Add-in API (see the solution explorer) and all relevant references

    //Use all relevant references

    using System.Drawing;

    using System.Windows.Forms;

    using Microsoft.Dynamics.Framework.UI.Extensibility;

    using Microsoft.Dynamics.Framework.UI.Extensibility.WinForms;

    //this is to let this add-in speech

    //http://msdn.microsoft.com/en-us/library/dd146744(v=office.13).aspx

    using System.Speech;

    using System.Speech.Synthesis;

    namespace NSpeech

    {

        //Develop the control add-in class.

        //Assign a name to the control add-in (MyCompany.MyProduct.MyAddIn)

        [ControlAddInExport("Cronus.DynamicsNAV.NSpeech")]

        [Description("Let this Add-in Speak")]

      

        //Select a base class as a starting point.

        //Select interfaces to implement features, such as data binding or event handling.

        public class Class1 : StringControlAddInBase

        {

            //Implement control creation

            protected override Control CreateControl()

            {

                //Create a brand new TextBox

                TextBox control = new TextBox();

               

                //Define TextBox size

                control.MinimumSize = new Size(50, 0);

                control.MaximumSize = new Size(500, Int32.MaxValue);

               

                //Add a DoubleClick event for the TextBox

                control.DoubleClick += new EventHandler(control_DoubleClick);

                return control;

            }

            //Define a voice synth

            private SpeechSynthesizer synth;

            private void control_DoubleClick(object sender, EventArgs e)

            {

                //create a new speech synth and set default audio device

                synth = new SpeechSynthesizer();

                synth.SetOutputToDefaultAudioDevice();

               

                //Pass TextBox content in a string variable

                string data = this.Control.Text;

              

                //... and let NAV speak it!

                synth.SpeakAsync(data);

            }

        }

    }

    E. Build the NSpeech.dll

    1. Once you have all setup, you are ready to build your Client Add-In. Go to Build > Build NSpeech

    F. Place DLL into Add-in folder

    1. Locate/copy/paste NSpeech.dll (should be in your C:\TMP\NSpeech\NSpeech\bin\Debug folder) to the Add-ins folder of a machine where the RoleTailored client has been installed

    (typically the Add-ins folder is here: C:\Program Files\Microsoft Dynamics NAV\60\RoleTailored Client\Add-ins)

    G. Determine the PKT (Public Key Token) of NSpeech

    1. Launch the Visual Studio Command Prompt
    2. In the VSCP:

    Sn –T “C:\TMP\NSpeech\NSpeech\bin\Debug\NSpeech.dll”

    In the following example, 250f71f35a467631 is the PKT (Public Key Token) needed to register the Add-in into NAV. (You will have another value.)

    NSpeechSn

    H. Register the NSpeech dll

    1. Open Classic Client
    2. Open Object Designer (SHIFT+F12)
    3. Select Table object (ALT+B)
    4. Run Table 2000000069 Client Add-in
    5. Insert a new line with these values:
    Field Value
    Control Add-in Name Cronus.DynamicsNAV.NSpeech
    Public Key Token 250f71f35a467631 (this is an example)
    Version 1.0.0.0
    Description Let this Add-in Speak

    How to Use This Add-in

    As an example, you can just let NAV speak the content of the field “Name” in Customer Card page (Page 21).

    1. Open Classic Client
    2. Go to Object Designer (SHIFT+F12)
    3. Select Page object (ALT+G)
    4. Design Page 21 Customer Card
    5. Go to Name Field and Edit properties (SHIFT+F4)
    6. Fill the ControlAddIn property with this value Cronus.DynamicsNAV.NSpeech;PublicKeyToken=250f71f35a467631 (change the PublickKeyToken value to the one that you have determined at step G.)
    7. Save and compile the page (CTRL+S)

    Now…you are ready to let NAV speak the Customer Name from the customer card by simply double clicking on on the Name!

    This simple Client Add-in project may be used in, e.g.

    • Speak an alert if the availability of an Item is lower than expected in a document page (e.g. sales quote)
    • Speak an alert if a Customer exceeds assigned Credit Limit
    • Speak internal comments for an item, a vendor, a customer, wherever this is needed
    • … and many more

    This simple Client Add-in project may be enlarged, e.g.

    • It could be possible to set the volume of the voice
    • It could be possible to set the rate of the voice
    • It could be possible to select another voice instead of “Microsoft Anne” default in order to speak words with proper accent language
    • It could be possible to save a .wav file instead of speaking it or even perform both activities
    • … and many more

    These postings are provided "AS IS" with no warranties and confer no rights. You assume all risk for your use.

    Best Regards,

    Duilio Tacconi (dtacconi)

    Microsoft Dynamics Italy

    Microsoft Customer Service and Support (CSS) EMEA

  • Microsoft Dynamics NAV Team Blog

    Making a Page or Report Available from Search in the RoleTailored Client

    • 0 Comments

    In the RoleTailored client, the Search feature finds only pages and reports that are accessible from the navigation pane, which includes the Home button, Activity buttons, and Departments. So if you want to make a page or report available from search, then add it to the Home button, an Activity button, or Departments.

    For information about adding pages and reports to the Home Button and Activity buttons, see Home Button Overview and Creating Activity Buttons for the Navigation Pane in the MSDN library.

    To add a page or report to Departments, you add it to the MenuSuite object that is used by the RoleTailored client. For more information, see How to: Create and Modify a MenuSuite Object in the MSDN Library.

     

  • Microsoft Dynamics NAV Team Blog

    How to Transform a ListPlus Page Into a FactBox

    • 0 Comments

    In several places in NAV 2009 SP1, it has been used ListPlus pages in order to display two-dimension matrix. Those ListPlus Pages may be customized in order to be arranged as FactBoxes directly inside a main page (Document, Worksheet, etc.).

    The main concept of those kind of two-dimensional matrix pages is that they have a Page Part with a List that is updated every time a value is changed in the analysis parameter bounded to fields and/or variables that belongs directly to the ListPlus.

    This post will provide the basics on how to integrate the Item Availability by Location directly as FactBoxes instead of being called from RTC actions. The same concept may be applied to Item Availability by Period and Item Availability by Variant (and/or all of them together). In the example, the Planning Worksheet page is used as the main page.

    listplus1

    The next step will guide you through the modifications that need to be performed in order to arrange Page 492 “Item Availability By Location” as a FactBox. (In the standard Cronus this is called from an action present in the Related Information action group.)

    1. Rearrange Matrix Lines and configure Style property
      1. Design page 515 “Item Avail. by Location Lines”
      2. Below the Container line, add a new line of Field type. Fill in a name (e.g. “ItemNo”), a caption (e.g. “Item”) and populate SourceExpr property with Item.”No.” + ‘ ‘ + Item.Description
      3. Add some Style management: for this line change the Style property to “Favorable” and StyleExpr to TRUE

        listplus2

      4. In order to display in bold Matrix cells that contain values different from 0, add the following Boolean global variables (one for every possible Matrix Column). It is very important that for every Boolean variable, you also set the property (SHIFT+F4) “IncludeInDataset” to Yes.

        GRBool (for GrossRequirement StyleExpr)

        SRBool (for ScheduledReceipt StyleExpr)

        PORBool (for PlannedOrderReceipt StyleExpr)

        PABBool (for ProjAvailBalance StyleExpr)

        InvBool (for Item.Inventory StyleExpr)

        QPOBool (for Item."Qty. on Purch. Order" StyleExpr)

        QSOBool (for Item.”Qty. on Sales Order” StyleExpr)

        TOSQBool (for Item.”Trans. Ord. Shipment (Qty.)” StyleExpr)

        QTBool (for Item.”Qty. in Transit” StyleExpr)

        TORQBool (for Item.”Trans. Ord. Receipt(Qty.)” StyleExpr)

        EIBool (for ExpectedInventory StyleExpr)

        AvInvBool (for QtyAvailable StyleExpr)

        SRQBool (for Item.”Scheduled Receipt(Qty.)” StyleExpr)

        SNQBool (for Item.”Scheduled Need (Qty.)” StyleExpr)

        PORLBool (for PlannedOrderReleases StyleExpr)

        NetChBool (for Item.”Net Change” StyleExpr)

        listplus3 

      5. Create a new Function called “InitBoolean” and add this code:

        GRBool := GrossRequirement <> 0;

        SrBool := ScheduledReceipt <> 0;

        PORBool := PlannedOrderReceipt <> 0;

        PABBool := ProjAvailBalance <> 0;

        InvBool := Item.Inventory <> 0;

        QPOBool := Item."Qty. on Purch. Order" <> 0;

        QSOBool := Item."Qty. on Sales Order" <> 0;

        TOSQBool := Item."Trans. Ord. Shipment (Qty.)" <> 0;

        QTBool := Item."Qty. in Transit" <> 0;

        TORQBool := Item."Trans. Ord. Receipt (Qty.)" <> 0;

        EIBool := ExpectedInventory <> 0;

        AvInvBool := QtyAvailable <> 0;

        SRQBool := Item."Scheduled Receipt (Qty.)" <> 0;

        SNQBool := Item."Scheduled Need (Qty.)" <> 0;

        PORLBool := PlannedOrderReleases <> 0 ;

        NetChBool := Item."Net Change" <> 0;

      6. Add the Boolean value initialization in the OnAfterGetRecord() trigger at the bottom

        ExpectedInventory := AvailabilityMgt.ExpectedQtyOnHand(Item,TRUE,0,QtyAvailable,31129999D);

        END;

        InitBoolean; //Add this line

      7. For last, let this code work. In Page Designer, on each field for which you created a Boolean variable, change the Style property to “Strong” and in the StyleExpr property add the respective Boolean variable that you created in step d.
      8. Save and Compile the page.

       

    2. Add Availability by Location FactBox to Planning Worksheet.
      1. Design page 99000852 Planning Worksheet
      2. Go to last line and add a new Part type. Give this a name (e.g. IALL) and a caption (e.g. Availability By Location) and in the Properties for the line, fill in the PagePartID with “Item Avail. by Location Lines”
      3. Save and compile the page.

       

    3. Add the controls and code to update dynamically the Availability by Location FactBox
      1. Design page 99000852 Planning Worksheet
      2. Add these global variables
        Name DataType Subtype Length Option String
        ItemForIALL Record Item    
        Calendar Record Date    
        ItemPeriodLength Option     Day,Week,Month,Quarter,Year,Period
        AmountType Option     Net Change,Balance at Date
        ItemNo Code   30  
        DescDateFilter Text   30  
      3. Add the controls to manage the options for the Availability by Location FactBox by inserting those lines below the Container

        listplus4

        Type: Group, SubType: Group, Caption: Availability Options

        Type: Field, Caption: View by, SourceExpr: ItemPeriodLength, Style: Unfavorable, StyleExpr: TRUE

        Type: Field, Caption: View as, SourceExpr: AmountType, Style: Unfavorable, StyleExpr: TRUE

        Type: Field, Caption: Period, SourceExpr: DescDateFilter, Editable: FALSE

      4. Create a new Function called UpdateSubForm() and add this code

        ..

        IF ItemForIALL.GET(ItemNo) THEN BEGIN

          FindPeriod('',ItemForIALL);

          CurrPage.IALL.FORM.Set(ItemForIALL,ItemPeriodLength,AmountType);

        END;

      5. Create a new Function called FindPeriod() with these values:

        FindPeriod(SearchText : Code[10];VAR ItemRec : Record Item)

        On the FindPeriod function, add a local variable:

        Name DataType Subtype
        PeroidFormMgt Codeunit PeriodFormManagement

        And add this code to the FindPeriod function:

        IF ItemRec.GETFILTER("Date Filter") <> '' THEN BEGIN

          Calendar.SETFILTER("Period Start",ItemRec.GETFILTER("Date Filter"));

          IF NOT PeriodFormMgt.FindDate('+',Calendar,ItemPeriodLength) THEN

            PeriodFormMgt.FindDate('+',Calendar,ItemPeriodLength::Day);

          Calendar.SETRANGE("Period Start");

        END;

        PeriodFormMgt.FindDate(SearchText,Calendar,ItemPeriodLength);

        IF AmountType = AmountType::"Net Change" THEN BEGIN

          ItemRec.SETRANGE("Date Filter",Calendar."Period Start",Calendar."Period End");

          IF ItemRec.GETRANGEMIN("Date Filter") = ItemRec.GETRANGEMAX("Date Filter") THEN

            ItemRec.SETRANGE("Date Filter",ItemRec.GETRANGEMIN("Date Filter"));

        END ELSE

          ItemRec.SETRANGE("Date Filter",0D,Calendar."Period End");

        DescDateFilter := ItemRec.GETFILTER("Date Filter");

      6. Now you only need to add the code to let the Availability by location FactBox act like the original ListPlus page. To do so, you just have to copy paste those functions (and obviously code inside) from Page 492 “Item Availability by Location” and paste them into the functions of the Planning Worksheet page.

        PeriodItemPeriodLengthOnPush

        YearItemPeriodLengthOnPush

        QuarterItemPeriodLengthOnPush

        MonthItemPeriodLengthOnPush

        WeekItemPeriodLengthOnPush

        DayItemPeriodLengthOnPush

        NetChangeAmountTypeOnPush

        BalanceatDateAmountTypeOnPush

        DayItemPeriodLengthOnValidate

        WeekItemPeriodLengthOnValidate

        MonthItemPeriodLengthOnValidat

        QuarterItemPeriodLengthOnValid

        YearItemPeriodLengthOnValidate

        PeriodItemPeriodLengthOnValida

        NetChangeAmountTypeOnValidate

        BalanceatDateAmountTypeOnValid

      7. Once you have copied all this function, it’s needed to substitute all the FindPeriod(‘’); statement with FindPeriod(‘’,ItemForIALL); (You can simply use CTRL+H, Replace build in function).
      8. For refinement, you need to add in the OnOpenPage() trigger, in the bottom, this code

        ...

          ERROR('');

        ReqJnlManagement.OpenJnl(CurrentWkshBatchName,Rec);

        FindPeriod('',ItemForIALL); //Add this line

        And in the OnAfterGetRecord(); trigger, in the bottom, this code

        PlanningWarningLevel1OnFormat;

        ItemNo := "No."; //Add this line

        UpdateSubForm; //Add this line

      9. Save and compile the page.

       

    4. Add the Period Actions to browse through Periods in the Availability by Location FactBox
      1. Design page 99000852 Planning Worksheet
      2. Go to Last line(the first blank line) of the page and click SHIFT+F4 (edit Properties of the page)
      3. Change the property PromotedActionCategoriesML into ENU=New,Process,Reports,Availability Periods
      4. Close the Page properties window
      5. Go to last line of the page and click on View > Actions
      6. Go to last line and add one action group and two actions like these

        listplus5

        Type: ActionGroup, Caption: Availability

        Type: Action, Caption: Previous Period, Image: PreviousRecord, Promoted: Yes, PromotedCategory: Category4, ShortCutKey: CTRL+Q

        Type: Action, Caption: Next Period, Image: NextRecord, Promoted: Yes, PromotedCategory: Category4, ShortCutKey: CTRL+W

      7. Save and compile the page.

    Right now you have completed all the steps necessary to create a FactBox for Item Availability by Location.

    Attached you will find a .txt file with the example above, extended to Item availability by Location, by Period and by Variant too. Captions have been added for ENU and ITA.

    These postings are provided "AS IS" with no warranties and confer no rights. You assume all risk for your use.

    Best Regards,

    Duilio Tacconi (dtacconi)

    Microsoft Dynamics Italy

    Microsoft Customer Service and Support (CSS) EMEA

Page 1 of 1 (3 items)