MVC Framework Basic Tutorial

This is a tutorial designed to help you get started working with the MVC Framework. In this tutorial, we will be developing a very simple progress bar plug-in, and will run it using the MVC Shell application framework. This tutorial assumes a working knowledge of Microsoft .NET, C# programming, and Visual Studio.

Making your first plug-in

Developing using the MVC Framework is based around the idea of plug-ins. While the MVC Framework is flexible enough to allow you to create your own MVC applications, using MVC Shell's plug-in interface allows the developer to ignore the work of developing application infrastructure, and focus instead on the logic and implementation of your plug-in.

In this tutorial, we will be developing a very simple plug-in that updates a progress bar. In building this tutorial, we will exercise most of the core components of the MVC Framework.

Setting up your project

We will begin by creating a standard Visual Studio project. The important thing to remember here is that a plug-in should be setup as a class library, not an application.

tutorial1.bmp

Now add MVC Framework as a reference.

tutorial2.bmp

Requests

Now create a folder in the project called "Requests" and create a new class called StartProgressRequest. This request will be sent by the view to initiate the progress bar sequence. Define the class as follows:

using System;
using System.Collections.Generic;
using System.Text;
using Sandia.MVCFramework.Request;

namespace TutorialPlugin.Request
{
    public class StartProgressRequest : AbstractStandardRequest
    {
        protected override void initParameters()
        {
            // No parameters needed...
        }
    }
}

This is an empty request in that it has no request parameters. If we had needed to pass some data with the request, we would have needed to add parameters. However, in this case no parameters are needed.

Data

Now we will create the progress data that is returned to the view in response to the StartProgressRequest. Create a folder in the project called "Data" and a new class called ProgressData. Define the class as follows:

using System;
using System.Collections.Generic;
using System.Text;
using Sandia.MVCFramework.Data;

namespace TutorialPlugin.Data
{
    public class ProgressData : IData
    {
        int progress;

        int Progress
        {
            get
            {
                return this.progress;
            }
        }

        public ProgressData(
            int progress)
        {
            this.progress = progress;
        }
    }
}

As you can see. IData is an empty interface used to define classes that are able to be processed in MVC. This simple class defines an IData that carries progress information using an integer.

The Data Analyzer

Now we will create the backend for this simple plug-in. Create a new folder in the project called "DataAnalyzer" and add to it a class called ProgressDataAnalyzer. This class should inherit from Sandia.MVCFramework.DataAnalyzer.AbstractStandardDataAnalyzer. We will break this class down into pieces, as it is a bit more complex.

We begin with DesiredRequests. This field is used to inform MVC Framework which requests this data analyzer is able to process. In this case, we want the class to process StartProgressRequests, so we add that type to a list and return it as follows:

public override IList<Type> DesiredRequests
{
    get 
    {
        List<Type> desiredRequests = new List<Type>();
        desiredRequests.Add(typeof(StartProgressRequest));
        return desiredRequests;
    }
}

In the same way, you can use DesiredSubscriptions to subscribe to various IData types. However, in this case, no subscriptions are needed, so we return an empty list as follows:

public override IList<Type> DesiredSubscriptions
{
   get { return new List<Type>(); }
}

The HandlePublishedData method is used to process incoming data. Since we have no data subscriptions to process, this method is also empty.

public override void HandlePublishedData(
    DataPacket dataPacket)
{
    // Nothing to do...
}

The Start method is called once MVC Framework has initialized and it is OK to send requests and publish data. This method allows objects to send initialization requests or data and perform other startup tasks. For this class, no initialization is necessary, so this method is also empty.

public override void Start()
{
    // Nothing to do...
}

Now we get to the interesting part, the processRequest method. Here is where the data analyzer will receive and process StartProgressRequests. Here is the code:

protected override void processRequest(
    IRequest request)
{
    StartProgressRequest spr = request as StartProgressRequest;
    if (spr != null)
    {
        for (int i = 0; i <= 100; i += 10)
        {
            ProgressData pd = new ProgressData(i);
            DataPacket dp = new DataPacket(pd, request.RequesterID);
            this.publisher.PublishData(dp);
            Thread.Sleep(2000);
        }
    }
}

As you can see, we check to see if the incoming request is a StartProgressRequest. Then the code starts a loop publishing larger and larger progress data with a delay in between. This simple code illustrates how to receive and process a request, and publish a result.

The View

Now to work on the front-end of this plug-in. We begin with the view. This simple view will have a button to start the progress sequence, and a progress bar to display the results. Begin by creating a new folder in the project called "View" and add a class called ProgressView. This class should implement AbstractStandardView. We will break this class down as before.

We begin with desired subscriptions. In this case we want to subscribe to ProgressData, so we add the type to a list and return it as follows:

public override IList<Type> DesiredSubscriptions
{
    get 
    {
        List<Type> desiredSubscriptions = new List<Type>();
        desiredSubscriptions.Add(typeof(ProgressData));
        return desiredSubscriptions;
    }
}

Since the abstract class' constructor is not empty, we need to pass some information along to it.

public ProgressView(
    IRequestRouter requestRouter,
    IPublisher publisher)
   : base(requestRouter, publisher)
{
}

Now we create the GUI components of the view. We begin by defining the progress bar. This is what will be updated after every publish.

private ProgressBar progressBar;

Now we define the setupView method, where we setup the GUI components.

protected override void setupView()
{
    Button startButton = new Button();
    startButton.Text = "Start";
    startButton.Click += new EventHandler(startButton_Click);

    this.progressBar = new ProgressBar();

    FlowLayoutPanel flp = new FlowLayoutPanel();
    flp.Dock = DockStyle.Fill;
    flp.Controls.Add(this.progressBar);
    flp.Controls.Add(startButton);

    this.Controls.Add(flp);
}

Here we define a button and a progress bar and add them to a FlowLayoutPanel. We then add the panel to the view. Now let's implement the button's click event:

void startButton_Click(object sender, EventArgs e)
{
    StartProgressRequest spr = new StartProgressRequest();
    this.requestRouter.RouteRequest(spr);
}

When the button is clicked, we construct a StartProgressRequest and send it.

Now let's set up the HandlePublishedData method. We follow essentially the same pattern as with processRequest earlier by checking the data type and then updating the progress as follows:

public override void HandlePublishedData(
    DataPacket dataPacket)
{
   ProgressData pd = dataPacket.Data as ProgressData;
   if (pd != null)
   {
      this.progressBar.Value = pd.Progress;
   }
}

Since we don't need to do any initialization requests, the Start method remains empty.

The View Manager

In the MVC Framework design pattern, views are arranged and organized by a view manager. Now let's define a view manager for this plug-in. Begin again by creating a "ViewManager" folder and a class called ProgressViewManager. This class should extend AbstractStandardViewManager. AbstractStandardViewManager will take care of most of the heavy lifting for us.

Let's begin with the constructor. Again, because the superclass constructor is not empty, we need to pass some information along:

public ProgressViewManager(
    IRequestRouter requestRouter,
    IPublisher publisher)
    : base(requestRouter, publisher)
{
}

Now add the ProgressView as a member of this view manager.

private ProgressView progressView;

A few of these methods we aren't using in this example. However, it is worth noting what they are used for. The method handlePublishedData is called by the superclass to allow the view manager to process incoming data. If True is returned, the superclass does not pass the data along to the views. This provides a way for view managers to block publishes to it's views.

The methods mainPanelHeightChanged and viewSizeChanged both provide ways that MVC Framework can notify the view manager of changes to it's state. These methods are often used for storing application settings.

Now, let's discuss the meat of this class. The function setupViewManager.

protected override void setupViewManager()
{
    this.progressView = new ProgressView(this, this);
    this.progressView.Dock = DockStyle.Fill;
    ViewLayoutNode progressNode = new ViewLayoutNode(this.progressView);

    StandardViewManagerState state = new StandardViewManagerState();
    state.MainLayout = progressNode;

    state.Views = new List<IView>();
    state.Views.Add(this.progressView);

    this.SetViewManagerState(state);
}

In this method, we initialize the ProgressView, and add it to the view manager's state. The superclass takes care of the rest of the layout of items for you.

The Plug-In

We have one more class to set up before this plug-in is complete. The plug-in definition class. Again, create a new folder called "Plugin" and add a class called ProgressPlugin. This class should extend AbstractStandardPlugin.

The first thing we should define is the plug-in's ID and display name:

public const string PLUGIN_ID = "C1F210AB-C8F4-457a-8E72-DFB82E0255F7";

public const string PLUGIN_DISPLAY_NAME = "Progress Plug-in";

public override string ID
{
   get { return ProgressPlugin.PLUGIN_ID; }
}

public override string DisplayName
{
    get { return ProgressPlugin.PLUGIN_DISPLAY_NAME; }
}

Now we need to define the loader version to use. There is currently only one version, so we set it up as follows:

public override long LoaderVersionToUse
{
    get { return 1L; }
}

Now let's add the DataAnalyzer.

private ProgressDataAnalyzer dataAnalyzer;

public override List<IDataAnalyzer> DataAnalyzers
{
    get 
    {
        List<IDataAnalyzer> dataAnalyzers = new List<IDataAnalyzer>();
        dataAnalyzers.Add(this.dataAnalyzer);
        return dataAnalyzers;
    }
}

Now the ViewManager.

private ProgressViewManager viewManager;

public override List<IViewManager> ViewManagers
{
    get 
    {
        List<IViewManager> viewManagers = new List<IViewManager>();
        viewManagers.Add(this.viewManager);
        return viewManagers;
    }
}

Now we need to initialize both of them.

public override void init(
   IRequestRouter requestRouter, 
   IPublisher publisher)
{
    this.dataAnalyzer = new ProgressDataAnalyzer();
    this.viewManager = new ProgressViewManager(requestRouter, publisher);
}

Now we define the Start method. We need to make sure and go through an start all the plug-in's components too (Note: This functionality will be moved into AbstractStandardPlugin in a future release).

public override void Start()
{
    foreach (IDataAccessor dataAccessor in this.DataAccessors)
    {
        dataAccessor.Start();
    }
    foreach (IDataAnalyzer dataAnalyzer in this.DataAnalyzers)
    {
        dataAnalyzer.Start();
    }
   foreach (IDataStore dataStore in this.DataStores)
   {
        dataStore.Start();
    }
    foreach (IViewManager viewManager in this.ViewManagers)
    {
         viewManager.Start();
     }
 }

That's it! Now just compile. The next section deals with how to run your plug-in using MVC Shell.

Running the plug-in

Now we turn to the task of running the plug-in using MVC Shell. This consists of two distinct steps, setting up and compiling the plug-in, and loading the plug-in in MVC Shell.

The MVC Shell is also open source, and can be downloaded from its site here.

Setting up and compiling the plug-in

We begin by setting up the plug-in to build in MVC Framework. First, exclude the MVC Framework DLLs from the build. These are already supplied by MVC Shell.

tutorial3.bmp

The next step is purely to make it easier to debug your plug-in. We set up Visual Studio so that the plug-in is put into it's own folder under the Debug directory. This allows you to make changes, recompile, and load the plug-in back into MVC Shell with ease, as you'll see later.

tutorial4.bmp

Now compile the plug-in, and we will move on to running it in MVC Shell.

Loading the plug-in in MVC Shell

To begin, start-up MVC Shell and go to Tools -> Options on the menu. From here, change the Plug-in source directory to .../TutorialPlugin/TutorialPlugin/bin/Debug as shown:

tutorial5.bmp

Now restart MVC Shell, and the plug-in will be downloaded from that directory. That's it, you should now be able to run your new plug-in!

tutorial6.bmp

Last edited Mar 25, 2009 at 8:50 PM by jtmcclain, version 20

Comments

No comments yet.