Colored tabs in Visual Studio

Do you have many tabs in Visual Studio with designers and code editors and do you struggle to make sense of them? It’s not surprising – we often work with many things at once and some elements even have same names (e.g. VendTable table and form), which means that tabs for them look identical.

Original view of tabs (no colors)

Wouldn’t it be great if, for example, tabs for tables had a different color than tabs for forms?

It can be done…

Open Visual Studio and go to Tools > Extensions and Updates. Switch to Online and find and install Productivity Power Tools.

Note that Power Tools contain many more features than just tab coloring. You probably want to review them and configure them as needed (which might also mean disabling some of them).

Open Tools > Options and switch to Productivity Power Tools > Custom Document Well. Uncheck Color tabs by project and tick Color tabs by regular expression.

Then go to Productivity Power Tools > Custom Document Well > Advanced and tick Use full document path for regular expression matching.

Then it’s time to define colors and rules for using them. The setup we’ve just done allows us to find patterns in paths of files used in tabs. For example, if I open VendTable table in the designer, the path (in my environment) is K:\AosService\PackagesLocalDirectory\ApplicationSuite\Foundation\AxTable\VendTable.xml. If I want to assign a color to all tabs with table designers, I can use a regular expression like .*\\AxTable\\.*. It finds paths containing \AxTable\.

This setup is done under Productivity Power Tools > Custom Document Well > Color Coding.

Here is an example of how we can use it.

Configuration of tab colors

Here I’ve decided to use different colors for designers and code editors. For example, a tab with table editor has a dark red color, while opening code for the table creates a tab with a lighter red color. The same is done for classes, just using green color instead of red.

This is what I can see in Visual Studio:

Colored tabs

Now I can clearly distinguish element types and if I remember my setup, I can even immediately say which tab is for which type.

By the way, I could also go to Custom Document Well options and set Place tabs on the Left to display tabs vertically:

Vertical tabs

If you prefer, you can set colors based on something else than element types. For example, you could use different colors for elements from different packages. You’re limited only by what information you can extract from file paths.

It works nicely in both Visual Studio 2015 and Visual Studio 2017. Unfortunately it’s not supported in Visual Studio 2019, although there seem to be ways how to get it working.

FormObservableLink works in data source extensions

FormObservableLink class is useful for refreshing display and edit methods in D365FO. You create an instance variable of FormObservableLink type in a form, initialize it and call its observe() method in display/edit methods that you need to refresh on demand. When the refresh is required, you call markChanged() method of FormObservableLink and the system will rerun the methods and display new values. You can find more details in AX 7. Display methods and Form Observability, for instance.

I wondered if I can do the same in a data source extension and I wasn’t really should that it would work. But it does – and the implementation is virtually the same as when building a whole form.

Here is a simple example:

[ExtensionOf(formDataSourceStr(smmContactPerson, ContactPerson))]
final class MySmmContactPerson_ContactPersonDs_Extension
{
    // Declare and initalize FormObservableLink
    private FormObservableLink observableLink = new FormObservableLink();
 
    edit NoYes myMethod(boolean _set, ContactPerson _contactPerson, NoYes _newValue)
    {
        // This says that observableLink will be able to refresh myMethod()
        observableLink.observe();
 
        ....
    }
 
    void refreshMethodsWhenSomethingHappened()
    {
        // Here we trigger a refresh
        observableLink.markChanged();
    }
}

‘is’ and ‘as’ operators with .NET types

I recently ran into an unfortunate limitation of .NET Interop from X++ (in D365FO).
I wanted to check if an X++ object is of a given type, nevertheless the type used for the variable declaration was a .NET interface. Here is an example:

using Microsoft.Dynamics.ApplicationSuite.FinancialManagement.Currency.Framework;
 
void demo(IExchangeRateProvider _provider)
{
    if (_provider is ExchangeRateProviderCBOE) {}
}

Exchange rate providers are X++ classing implementing IExchangeRateProvider interface and I wanted to check if the object I received was a particular provider (namely ExchangeRateProviderCBOE class or its child). Unfortunately this ended up with a compilation error:

The operand on the left side of the ‘is’ or ‘as’ operator must be a table, class, or form.

As I tested, neither managed interfaces nor managed classes (such as System.Object) can be used on the left side of ‘is’ and ‘as’ operators.

I solved the problem by using Type.IsAssignableFrom() method. Simply using the ‘is’ operator would be nicer, but this does the job too.

void demo(IExchangeRateProvider _provider)
{
    System.Object providerObj = _provider;
    if (providerObj.GetType().IsAssignableFrom(new ExchangeRateProviderCBOE().GetType())) {}
}

Note that the problem is only with the left side of the operators, e.g. when you want to check whether a managed type is this or that. Using the ‘is’ operator to check if an instance of an X++ class implements a managed interface works without problems.

Object obj = new ExchangeRateProviderCBOE();
if (obj is IExchangeRateProvider) {}

Exception handling in PU31

In 2018, I wrote the blog post Throwing managed exceptions from X++ in D365FO, where I pondered upon how throwing proper exceptions objects in X++ would be beneficial. This is still true. I also showed a proof of concept how it can be done despite the fact that X++ doesn’t directly support it. But this has changed! Platform Update 31 has introduced the possibility to throw managed (CLR) exceptions directly with the throw statement.

Therefore you can now do things like this right from X++:

throw new System.ArgumentException('A value must be set', 'FromDate');

Then you can react to this particular type of exception and you’ll also get a lot of context, such as which argument is wrong. For example:

System.ArgumentException argEx;
 
try
{
    ...
}
catch (argEx)
{
    warning(strFmt("Please provide a valid value for the parameter '%1'.", argEx.ParamName));
}

If you want to define your own exception class (e.g. FieldEmptyException from my previous blog post), you still can’t do it in X++ – you need a C# project or something. And it’s probably not going to change. But it shouldn’t be a big problem, because working with C# projects in D365FO is very easy.

PU31 added one more ability of throw. Imagine that you want to log an exception, but you don’t want to handle it. You catch it, log it and then you can throw another exception. But this new exception won’t have the same properties as the original one, e.g. its stack trace will show that it was thrown from your catch clause. To rethrow the same exception, use throw without any argument. Like this:

catch (ex)
{
    logger.log(ex);
    throw;
}