Twenty different Menu Suites

In an effort to give better support to NAV Extensions Microsoft have added support for ten more MenuSuite objects.

MenuSuites

I have given my opinion to Microsoft on the MenuSuite design and how it could be improved.  I guess everything can be improved in one way or another.

To quote Microsoft: “This simple update doesn’t pretend to solve the underlying problem described. It mitigates by doubling the number of add-ons to 20, already accounted for in existing licenses. We are aware that this is not the long term solution, but it is a quick way to mitigate some partners’ problems with MenuSuites and Add-ons.” 

Mr. Singelton I presume

We do have one Mr. Singelton in our Dynamics NAV MVP group.  However, this blog post is not about him.

Singelton is a well known Design Pattern.  A Singelton object is a one instance object that is shared in the whole application.  Vjeko showed an example of this in his recent post.

With a Singelton class it is possible to store values that can later be retrieved by another call not related to the first.

It is common practise in Dynamics NAV to create a single-instance Codeunit to keep data that needs to be accessible from all processes within the user session.  A Singelton class is common for all user sessions on the server.

The example Vjeko talks about it that you can store data in a Singelton class to implement a state information into an otherwise stateless web service.

In a recent post I talked about a Variable Store Codeunit.  That was a single-instance Codeunit where I used the DotNet Dictionary to store and retrieve values.  This worked well inside a single user session.

I wanted to make a similar functionalilty available as a Singelton class that would be common for all sessions.  The class code is in c#

[code lang=”csharp”]using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SingeltonDictionary
{
public class SingeltonDictionary
{
private static SingeltonDictionary instance;
private Dictionary<string, string=""> NavDictionary = new Dictionary<string, string="">();

private SingeltonDictionary() { }

public static SingeltonDictionary Instance
{
get
{
if (instance == null)
{
instance = new SingeltonDictionary();
}
return instance;
}
}
public bool AddToDictionary(string KeyName, string Value)
{
if (NavDictionary.ContainsKey(KeyName))
return false;
else
{
NavDictionary.Add(KeyName, Value);
return true;
}
}
public void AddReplaceInDictionary(string KeyName, string Value)
{
ClearFromDictionary(KeyName);
NavDictionary.Add(KeyName, Value);
}
public bool ClearFromDictionary(string KeyName)
{
if (NavDictionary.ContainsKey(KeyName))
{
NavDictionary.Remove(KeyName);
return true;
}
else
return false;
}
public bool GetFromDictionary(string KeyName, ref string Value)
{
return NavDictionary.TryGetValue(KeyName,out Value);
}
public void ClearDictionary()
{
NavDictionary.Clear();
}
}
}
[/code]

The Singelton Dictionary NAV add-in can be downloaded here -> Microsoft.Dynamics.Nav.SingeltonDictionary

There is another reason why I wanted to create this add-in.  I have a solution for the Windows Client to be able to easily create textboxes and buttons for a NAV Page.  One of the problems with this add-in can be solved with a Singelton class.

The solution has a Panel Class that is built when the add-in is initiated on the page.  On top of that panel any number of buttons and textboxes are added dynamically.  To support this the panel has the autosize property set and will resize as needed.

The problem is that you can’t start to add things to the panel until it has been initiated and at that time NAV draws the page and decides how much space is needed for the panel.  At the time NAV decides the panel is empty and therefore no space is allocated for the panel.

It is not possible to change a property or call a method on the add-in until the add-in is ready and the page has been created.  So, here I solve this by using the Singelton class.  I make the Singelton add-in a reference in the Buttons & TextBoxes add-in and the Singelton class can be accessed the whole time.

In my NAV Page I added the Singelton NAV add-in as a client-side DotNet variable and added three lines of Singelton code.

SingeltonInit2

Similar in my Buttons & TextBoxes add-in I added two properties to read these Singelton values.

SingeltonGet

When the panel is created I make sure that I read these properties.

panelsize

It is important to use the XML format in NAV when using this Singelton Dictionary.  Make sure to always use FORMAT(<value>,0,9) and on the other side use EVALUATE(<value>,SingeltonValue,9).

Evaluate

 

 

Waiting for a server warmup – no more

One of the problems NAV users face is that the client is to slow after the NAV service starts.

The reason for this is that NAV uses just-in-time compilation of the source code.  The source code is compiled on the server when the server needs to use it.

If you want the server to be warm when the demoing NAV you need to make sure that the server compiles all needed code before showing off.

On the Microsoft Dynamics NAV 2015 Azure Demo Template you can see that Microsoft has added a WarmUp script to take care of this problem.  This solution includes a solution that will open a list of pages with the web client to make sure that the server compiles the basic functionality for the demo.

If you want to play with this yourself on your own installation just download the zipped warmup folder (WarmupNAV) and start investigating.

Run a Table in NAV

One of the things we developers and consultants miss the most from the “Classic Times” is the ability to run a table to edit the data. Sure we can run a table from the Developement Environment but we are not always working with direct access to the SQL database.

My solution is to have a Page running on the object table (Table2000000001). From the page I can start Pages, Reports, Codeunits and XML Ports directly with a simple line of code, but to start a Table is more complex.

The first solution was to use HYPERLINK on the result from the GETURL function. That works fine in a local environment, but when you have installed multiple Dynamics NAV versions or running Dynamics NAV from a ClickOnce installation things start to break.

To fix this I stop using HYPERLINK and start the Dynamics NAV client with arguments to run a table. First step is to find the current client path. This path can be the usual System Drive path but it can also be a User Application Path if using ClickOnce. The function to locate the client path uses DotNet.

[code] PROCEDURE GetClientPath@1100408003() : Text;
VAR
ClientAssembly@1100408001 : DotNet "’mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′.System.Reflection.Assembly" RUNONCLIENT;
ClientPath@1100408000 : DotNet "’mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′.System.IO.Path" RUNONCLIENT;
BEGIN
ClientAssembly := ClientAssembly.GetExecutingAssembly;
EXIT(ClientPath.GetDirectoryName(ClientAssembly.Location));
END;[/code]

And based on the client Path I look for the ClientConfiguration.config file and start the client with the GETURL results.

[code] LOCAL PROCEDURE ViewRecords@1100408000();
VAR
AddinMgt@1100408000 : Codeunit 10000207;
PathHelper@1100408008 : DotNet "’mscorlib’.System.IO.Path";
ClientFileHelper@1100408007 : DotNet "’mscorlib’.System.IO.File" RUNONCLIENT;
ClientProcess@1100408005 : DotNet "’System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′.System.Diagnostics.Process" RUNONCLIENT;
ClientProcessWindowStyle@1100408004 : DotNet "’System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′.System.Diagnostics.ProcessWindowStyle" RUNONCLIENT;
ClientProcessStartInfo@1100408003 : DotNet "’System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′.System.Diagnostics.ProcessStartInfo" RUNONCLIENT;
StartCommand@1100408002 : Text;
ArgumentList@1100408006 : Text;
ClientPath@1100408001 : Text;
ClientConfigurationPath@1100408009 : Text;
BEGIN
ClientPath := AddinMgt.GetClientPath;
ClientConfigurationPath := PathHelper.Combine(ClientPath,’ClientUserSettings.config’);
IF ClientFileHelper.Exists(ClientConfigurationPath) THEN
ArgumentList := STRSUBSTNO(‘-settings:"%1" ‘,ClientConfigurationPath);
ArgumentList += GETURL(CLIENTTYPE::Windows, COMPANYNAME, OBJECTTYPE::Table, ID);
ClientPath := PathHelper.Combine(ClientPath,’Microsoft.Dynamics.Nav.Client.exe’);
ClientProcessStartInfo := ClientProcessStartInfo.ProcessStartInfo(ClientPath);
ClientProcessStartInfo.Arguments := ArgumentList;
ClientProcessStartInfo.WindowStyle := ClientProcessWindowStyle.Normal;
ClientProcess := ClientProcess.Start(ClientProcessStartInfo);
END;[/code]

To repeat my last comment, just use DotNet 🙂

Selection Filter to Clipboard

I have now seen three posts about using Excel to help create a Pipe Filter.  The latest one from Mohana is similar to the way I normally do this.  His post is a followup from the original video from Kerry Rosvold and an alternative from Mark Brummel.

If this is something you frequently need to do, why don’t use NAV and skip the Excel part ?

Lets imagine how that could look like.

CustomerList

We add a button the ribbon, select what ever we like from the customer list and click the button.

Clipboard

Now it just a matter of using the filter. Paste it where ever you need it.

FilteredCustomerList

And this is with just a few lines of code.

CustomerListModification

Page21 Delta file

My first dynamic Windows Client Add-in

I have a task where a user on a Windows Client wants to use his touch screen to select from a limited set of Items.  In NAV 2009 R2 this was a form with buttons and I have been waiting to update this to NAV 2013 R2 until I had finished most of the other tasks for that client.  That time is now.

I attended the session on Directions EMEA where Vjeko presented client extensions.  I also saw a post by Rashed on his mibuso blog about buttons.

So I started the task.  I have done several add-ins for NAV so I know enough about Visual Studio to feel comfortable using it.  Of course, when ever one starts something like this there is always something new to learn and use.  To search for help on C# on the internet is really helpful and we have a lot of good examples out there.

Like Rashed, I created a panel that hosted all the buttons and text boxes and that panel is the object added to the NAV page.

Panel

I wanted to be able to customize all the buttons and text boxes from NAV so I created default values and null able values for all my properties.  Then I created a property for every value that I wanted NAV to have access to in the class.

Property

After I created the panel control I wanted a trigger to fire in NAV to tell me that the add-in was ready.  I followed the example Vjeko gave in last Directions but that simply did not work.  I contacted him and that resulted in a new blog on Vjeko’s site.  Instead of triggering an event when creating the control the trigger is now fired after the control is bound to the NAV page.

PanelChanged

When I get the trigger fired in NAV I create the buttons with all the properties I need.

CreateButtons

The test page I created will allow me to select any number of buttons and/or text boxes.  I can customize background and foreground color, font family and font size.  Some of these settings can be done for each button or text box individually, that is the ones included in the arrays used when calling the CreateButtons function with arrays create from the Item table using these settings.

TouchScreen

 

 

In the add-in I have created two event handlers to handle the push of a button or a text change.

EventHandlers

This is handled in the NAV page with this code.

NAVEvent

So when I press a button or change a text I will get a message from NAV.

I also made sure that if I select zero as a size for either the buttons or the text boxes they will not show.

OnlyButtons

OnlyTextBoxes

I have adapted a new method when sharing objects and information.  I will publish on my blog how things are done if you want to create your own version and will also supply a version you can download and start using at Objects4NAV.com.

Automatic Deployment of Microsoft .NET Framework Interoperability and Control Add-in Assemblies in NAV 2015

Sitting here at the airport in Copenhagen with my laptop waiting for my ride home to Iceland.

I wanted to write about a topic that I did not hear or see in Directions during this week.  Windows Client add-ins are now automatically downloaded from the server to the client if they are needed.

A fellow MVP Arend-Jan has already blogged about this but I want to explain a little bit more.

There are a few rules to follow to make sure that this works.  First is the assembly name.  The assembly name must be “Microsoft.Dynamics.Nav.Client.<Class Name>” if the server is supposed to find it.

AssemblyName

Put each new assembly in a dedicated folder in the server add-ins folder.  If other components are needed for this assembly then put them in the same folder.  The server will copy the whole folder to the client.

UserHelperFolder

In the Developement Environment make sure that your server is selected in Tools-Options.

DevToolsOptions

Then when looking for an assembly a new option is to look in the server add-ins folder.

AssemblyLookup

Adding an assembly into your code to run at the client will now work without any further actions.

HelperClassInTable370

And now – when I print to Excel the new Excel window opens in front of Dynamics NAV 2015.

iExcelInFront

 

To quote Microsoft directly:

“Automatic Deployment of Microsoft .NET Framework Interoperability and Control Add-in Assemblies

Microsoft Dynamics NAV 2015 makes it easier for the system administrators to deploy client-side assemblies for .NET Framework interoperability and client control add-ins on computers that are running the Microsoft Dynamics NAV Windows client or Microsoft Dynamics NAV Development Environment. You can now install the assemblies in the Add-ins folder on the computer that is running Microsoft Dynamics NAV Server. By default, this is the C:\Program Files\Microsoft Dynamics NAV\80\Service\Add-ins folder. When an operation from the client requires an assembly, Microsoft Dynamics NAV Server automatically deploys the assembly to a temporary folder on the client computer.

For example, if Microsoft Dynamics NAV Windows client opens a page that contains a control add-in, Microsoft Dynamics NAV Server will find the control add-in assembly by name in the Add-ins folder. Then, it deploys the assembly to the client computer in the %TEMP%\Microsoft Dynamics NAV\Add-Ins folder of user who is running the client. Subsequently, the deployed assembly will be used whenever the page is opened.

Similarly, if the development environment requires a control add-in, for example, when you compile an object, then the control add-in assembly will be deployed by the Microsoft Dynamics NAV Server to the local temporary folder for the current user on the computer that is running the development environment.

Note
To be deployed, an assembly must comply with the following Microsoft Dynamics NAV Server configuration settings: Chuck Size, Max Upload Size, and Prohibited File Types.

If a .NET Framework interoperability or control add-in assembly is updated and its version number changes, Microsoft Dynamics NAV Server will deploy the updated assembly to the client computer the next time that the client requests the assembly. The updated assembly is put in a subfolder of the %TEMP%\Microsoft Dynamics NAV\Add-Ins folder, where the subfolder has the assembly’s version number as its name. This implementation means that you do have to remove the older versions of assemblies that are stored on the client computer.

To support compatibility with earlier version of Microsoft Dynamics NAV, before Microsoft Dynamics NAV Server deploys an assembly to a client, the client looks for the assembly in the local Add-ins folder (for example, C:\Program Files (x86)\Microsoft Dynamics NAV\80\RoleTailored Client\Add-ins). If the assembly is not found, then the client will request the assembly from Microsoft Dynamics NAV Server. Javascript-based client add-ins have been using this deployment technique since Microsoft Dynamics NAV 2013 R2.”

Scanning and attachments for Incoming Documents in Microsoft Dynamics NAV 2013 R2

A new feature in NAV 2013 R2 allows companies to store links to incoming documents and reference them in Purchase Invoices and Journal Lines.  There is a video in the How Do I series on Managing Incoming Documents in Microsoft Dynamics NAV 2013 R2.

I wanted to add a functionality to scan and store the files within NAV.  Using the Hardware Hub and the Hardware Hub Twain Client to easily scan documents and store them in NAV.  The objects needed are attached below.  You will need to put the Hardware Hub Proxy Add-in to the NAV 2013 R2 Server Add-in folder.  There is a possibility of doing this without the add-in by manually creating the soap requests.  I did this in the NAV 2009 R2 version for the Classic Client and if needed I should be able to make available a similar NAV 2013 R2 version.

So, how does it work ?

First step is to download and install the Hardware Hub Twain Client on the computer with a twain compatible scanner and the Hardware Hub Proxy Add-in to the Server Add-in folder..  Double click the icon in the notification area to get the program windows in foreground.  Next step is to install the new and modified objects into your NAV 2013 R2 database.

Then go to Incoming Document in the Windows Client.  After an incoming document entry has been created the New Attachment button will be enabled.NewIncomingDocumentEntry

Click New Attachment button.  The first time you open this page you will need to set up the scanner connection.

ScanningSetup

You need to compare the Hardware Hub Path and the Hardware Hub Scanner GUID to the Twain Client window.  It should be enough to copy the GUID from NAV to the Twain Client.

TwainClient

Minimize the Twain Client and go to the ACTIONS menu to select scanner.  You can test the Hardware Hub connection with the About action.

SelectScanner

These settings will be saved with the page data personalization for the current user.

If you select to “Show Settings” the settings dialog will sometimes appear behind the NAV Windows Client – just to let you know.

You can also browse for an existing file in the File Name drill down arrow and that file will be uploaded into NAV.  When you close this window the URL to the Incoming Document Store will be added to the Incoming Document.  You can add multiple files to a single Incoming Document and the URL will open all of them.

This solution will work on a cloud based NAV and also via remote desktop.  I was able to scan with the Web Client but that functionality is not fully tested.  Your feedback is always appreciated.

Objects: IncomingDocumentStore, 2014-07-29 Update

Hardware Hub IIS Service on Objects4NAV.com

Install Client and Server update with PowerShell

It is time to share with you the scripts that I am using to install and update the NAV application in the company network.  In the attached ZIP packages you will find a lot of files.

In the root folder I keep the settings files.  These files must be customized.  The folders are as follows;

  • Edge3-Internet – my internet facing server.  Here I install ClickOnce, WebClient and NAV Service.
  • Fjarvinna-Domain – my remote desktop server.  Here I install KB updates remotely.
  • Localhost-Domain – my intranet server.  Here I install NAV Service for the domain.
  • NAVCmdLets – my collection of PowerShell scripts for NAV.  Some a copied from the NAV DVD.
  • Install-KBLocally – scripts to install a KB package to the local computer.

If we first look at the Edge3-Internet folder, here I have scripts to remotely install NAV on a server.  I usually create a ClickOnce container in the folder ‘c:\inebpub\ClickOnce’ and keep all my ClickOnce subfolders in there.  In the Set-MachineSettings.ps1 file I set the machine name.

Next, in Fjarvinna-Domain folder I only have scripts to upload and install a KB package.  Also in here I have the Set-MachineSettings.ps1 to define the machine name.

The Localhost-Domain folder includes scripts to install NAV Service and NAV Users to the localhost.

Then there are the functions that I use in the above scripts.  In the NAVCmdLets folder I have a collection of scripts to handle ClickOnce, KB install and some SQL administration tasks.

Finally the Install-KBLocally folder.  As the name suggest, the contained scripts are used to install a KB package on the localhost.  I usually create a folder that contains this folder, the NAVCmdLets folder and for example the KB2955941 folder.  The KB2955941 can be downloaded from Microsoft.  I usually delete all sub folders except ADCS, NST, OUTLOOK, RTC and WEB CLIENT after I add this folder to the update package.

Also, in my KB package I have two CMD files.  One to install to a 64bit machine (default) and the other to a 32bit machine.  If you put this package on your network and modify the CMD files to point to the correct file share you should be able to use this for all the computers on the domain.  The KB package without the Microsoft binaries is attached below.  Make sure to right-click on the install CMD file and run as administrator for a succesful install.

If you are running an old operating system, you might need KB2506146 or KB2506143 installed before using the KB package.

With your network administration tools you should be able to use some of these scripts to install a KB package on all your domain computers to make sure that everyone is running the latest version recommended by Microsoft.

NAVPowerShellScripts KB

Browse for folder dialog

I have in several cases needed to allow a user to select a folder.  I was surprised to see that Microsoft did not have a browse for folder function in Codeunit 419.

I hereby suggest that Microsoft add this function to Codeunit 419.

[code] PROCEDURE BrowseForFolder@47(VAR FolderName@1000 : Text;Description@1001 : Text) : Boolean;
VAR
FolderBrowserDialog@1002 : DotNet "’System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′.System.Windows.Forms.FolderBrowserDialog" RUNONCLIENT;
DialagResult@1003 : DotNet "’System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′.System.Windows.Forms.DialogResult" RUNONCLIENT;
BEGIN
FolderBrowserDialog := FolderBrowserDialog.FolderBrowserDialog;
FolderBrowserDialog.Description := Description;
FolderBrowserDialog.SelectedPath := FolderName;
DialagResult := FolderBrowserDialog.ShowDialog;

IF DialagResult.CompareTo(DialagResult.OK) = 0 THEN BEGIN
FolderName := FolderBrowserDialog.SelectedPath;
EXIT(TRUE);
END;
EXIT(FALSE);
END;
[/code]