Code Available on GitHub

Part 3 Specific Code on GitHub

If you search Google for Dynamics NAV item pictures you will find that there are a few examples out there for easily associating a picture with an item. However, there is not much on displaying multiple images for an item. This is a challenge I had to solve for my employer. Many items had anywhere from a single image to 10+ images.

I decided to come up with a .Net add-in control that was able to display multiple images for any given item and on any page (e.g. the item list, item card and beyond). I have decided to create a tutorial to show you how to create such a control. This will be quite lengthy, so I will split it up into smaller parts for you to digest more easily. The tutorial will be split into the following 7 part series:

  1. Part 1 – Introduction
  2. Part 2 – Creating the .Net image control model
  3. Part 3 – Creating the .Net image control viewmodel (this post)
  4. Part 4 – Creating the .Net image control view
  5. Part 5 – Creating the .Net add-in control wrapper class
  6. Part 6 – Creating the Dynamics NAV Item Images factbox page
  7. Part 7 – Hooking up the item Images factbox page

Part 3 – Creating the .Net Image Control ViewModel

Initial Preparation Notes

In this part of the tutorial we will be creating the ViewModel objects and a couple supporting classes. If you haven’t already, I suggest you grab the source code from GitHub, so you can follow along. This will also allow me to skip going through the folder structure and project setup and focus on the code itself. Any other preparation steps and notes can be found in Part 2 of the tutorial.

ViewModelBase Class

The first thing to consider for a ViewModel class is the need to notify the View when bound properties have changed. This is done through the INotifyPropertyChanged interface. Unfortunately this can be tedious when implemented in the standard manner as suggested by Microsoft because it requires you to implement it for every ViewModel class that requires it. It is also error prone because you have to pass a string representation of the property name to the OnPropertyChanged method. To avoid this, most people create a base class that implements the INotifyPropertyChanged interface and then have all of their ViewModels inherit from this class.

There are a couple things to note here. First, we can avoid the error prone string parameter for the property name by using the [CallMemberName] attribute as the default parameter to the OnPropertyChanged method. This will expose the calling properties name and pass it in for us by default (no string spelling errors!). Second, thanks to ReSharper, a handy annotations class has been created for us (this is where the [NofityPropertyChangedInvocator] attribute comes from). I will not delve into this, but you can check out more information about it here. The annotations file is in the sample code on GitHub if you want to look at it. It is conveniently named Annotations.cs and is found under Properties in the solution explorer.

ImageViewModel Class

Our first real ViewModel class is the ImageViewModel. This is a simple class that wraps an image and exposes it through a property.

There is not much else to say about this class except that it inherits from the ViewModelBase class and you can see that it calls OnPropertyChanged (not needing to pass in the property name via a string) if the ItemImage property is changed.

RelayCommand Class

Another class that most people end up creating is some sort of command base class that Implements the ICommand interface. The ICommand interface simply says you must define a command’s execution behaviour (what executes when the command is invoked) and a predicate that returns whether or not a command is allowed to execute in it’s current state. There are many ways to implement this behaviour, but I lean towards Josh Smith’s RelayCommand (with some very slight differences, such as Func<bool> instead of Predicate<object> for CanExecute; this is just a personal preference).

PageableImageControlViewModel Class

This is the main ViewModel class (inherits from the ViewModelBase class) that will serve as the driver and glue between the main View and the various Model and supporting ViewModel classes. This is quite a large class so I will focus on certain sections, but not all.

Image Collection

The image collection portion of this class focuses on a SmartObservableCollection (discussed in Part 2) of ImageViewModels and the IImageRepository (also discussed in Part 2) used to populate the collection.

First off we have our collection of ImageViewModels, which notify the client whenever the collection has been changed. We also initialize our PageableImages, which will be discussed shortly.

The bottom half of the code shows the IImageRepository logic. This is set from outside of the ViewModel (it will be set from NAV) and provides the collection of images (which are then wrapped into ImageViewModels for display). Once the ImageViewModels are created, the PageableImages are initialized (again more on this shortly) and the main (large) image is set to display the first image on the list. As a fallback for if a collection of images does not exist for the current item, UseDefaultImage is called. In this tutorial, it will just create a blank image, but you could easily have a default image in the project resources or perhaps a file location.

Pageable Image Collection

We have a collection of images, but we don’t want to display them all at once. The approach I have taken is to create another collection that will hold the current page of images (page size can be configured).

We’ve seen calls to initialize the PageableImages collection a couple times in preceding code examples. I’ll show that now.

This method sets a couple properties that control whether or not we can move to the next page (CanPageNext) or to the previous page (CanPagePrevious). Since we are initializing the collection, we cannot move to the previous page (we are on the first page, hence CurrentPage = 0;). Whether or not we can move to the next page depends if we have more images than images allowed per page (PageSize). GetImages is a function that grabs images from the full Image collection and pulls out as many images as possible, but not exceeding the PageSize limit. We’ll get to that in a minute.

One final note on the InitPageableImages method. There is a call after the PageableImages are updated (via the Reset method) to OnPropertyChanged to notify the View that we have updated the images. However, since we are not calling this method from within the PageableImages property setter, we need to specify explicitly which property the View should be notified about. This is why the call to OnPropertyChanged has the PageableImages string as a parameter.

GetImages ensures we have an image collection (neither null nor empty). If is does not, an empty collection is returned. If we do have images, it does the following:

  • Multiplies the current page number by the number of images per page to get our starting point in the image collection for the current page.
  • Skips all images before that point.
  • Takes x number of images from that point (where x is the images per page or page size) and returns them in a collection.

For example, if we have a page size of 3 and our current page is 2 (0 based, so we are actually on the third page of images):

  • Skip 2 * 3 images (first six images)
  • Take next 3 images
  • In other words, for the third page, we are displaying images 7, 8 and 9.
Paging Commands

Time for the paging commands. These commands allow you to move forward and backward through the multiple images, a page at a time.

First up we have the CanPageNext property. This is just a boolean property with a backing field that is used to track whether or not PageNextCommand is allowed to be executed.

The PageNextCommand is actually an ICommand property with a backing field that is initialized as a RelayCommand, only if it is needed. In the getter, we check if _pageNextCommand (the backing ICommand field) is null. If not, we just pass it to the caller (or as you will see in the next part of the series, the button which is bound to the ICommand). If the backing field is null, we instantiate it by creating a new RelayCommand. The RelayCommand is passed the method to execute (PageNext) and a function to determine if the executing action is allowed to be invoked (CanPageNext). Don’t worry too much if syntax seems strange to you. This is just a way to wrap the function into a parameterless Func delegate that takes no parameters and returns a boolean.

The PageNext method itself is not too complicated. It increments the CurrentPage property, gets the next page of images, checks if there are enough images remaining to allow another PageNext execution, sets the CanPagePrevious to true (we just moved forward a page, so we can definitely move back a page) and notifies the View that the images have been updated.

The PagePreviousCommand is the inverse of the PageNextCommand so I will not cover it in the tutorial. You can look at the source code on GitHub if you are interested.

Image Display

The final piece I will cover in this tutorial is the image display logic. This is the code used to display the main (large) image and allows switching that image to another one.

This code is pretty much the same as what you have seen in the previous code examples. There is only one difference here that is worth noting:

In the SwitchImage method, we are passed an object, which we try to cast to an Image. If the cast succeeds (see using the as operator), we use it as a bitmap for the MainImageSource property. You’ll notice that the DisplayLargeImage command creates a RelayCommand like so:

_displayLargeImage = new RelayCommand(SwitchImage)

So where is this Object parameter coming from? It’s actually coming from the view as a CommandParameter binding (it will be the thumbnail image that was clicked in the which will then be displayed in the larger image). We will cover that in the next tutorial.

That’s it for Part 3. This was a bit longer than the previous parts, but this is where the main logic in the program is located. Next up: Part 4 – Creating the .Net image control view.

4 thought on “Dynamics NAV .Net Multi-Image Add-In Control Part 3 – Creating the .Net Image Control ViewModel”
    1. Thanks Arnaud! I’ll be posting the next part tomorrow night and will likely pump out the remaining parts a little quicker (finally a little more time available).

      1. Great ! It’s awesome what you did ! I didn’t realize it’s possible to do such things and integrate it into Nav. Just checked the forth part it’s great thanks 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.