Sunday, June 29, 2008

MVC (Model View Controller) Design Pattern - in the late 70's

In this article we will walk through the first two phases in the evolution of MVC. We'll review the Classic MVC pattern that was developed by Trygve Reenskaug for Smalltalk in the late 70's and see how it was evolved into Application Model MVC.
MVC Concept
MVC concept is to make a clear division between domain objects (model) and presentation objects (view and controller); it introduces the Observer-Synchronization mechanism to support multiple presentations (observers) of single domain object (observable) and to keep the domain objects completely unaware of their presentation objects.
Even though MVC had constantly improved over the last three decades - its concept remained unchanged.

Classic MVC

Entities
View is a widget on the screen surface, it can be a button, label etc. Its purpose is to display model data (usually one of its fields). It communicates directly with the model.
Bear in mind that we are talking about widgets of the 80's that are only about the display, they doesn't know if they are being clicked by the mouse or pressed by the keyboard.
Controller is a logical entity that always has view (widget) as a pair. It process user inputs coming from input devices such as keyboard and mouse and command the model as appropriate. It communicates directly with the model.
Model is a bunch of business objects that represent the problem domain.  Mainly, those objects stores data, interact with DB and services and handle business logic. It's completely ignorant of the UI, thus it doesn't know nothing about neither view nor controller.
Collaboration
The diagram bellow shows how MVC objects collaborate. The objects in the diagram represent the most simple UI that has two widgets (represented by the widget-controller pairs) and one business object (represented by the model).
The controller receives inputs from the user, if the input is relevant to its widget(view) pair - it command the model as appropriate, the model performs some business operation, changes its state and raise the proper event, the widget(view) respond to that event, ask relevant data from the model and changes its display.
image_thumb9
What you can't see in the picture above is that view has link to method in the model so it can retrieve data whenever the data changes, also, you can't see that controller and view are allowed to link each other directly.
Interaction
The 'Speaker Control' GUI that is shown bellow has one simple use-case. [Trigger:] The user click on the 'Increase Volume' button [Main Success Scenario:] the speaker volume is increased by one and the text-box display is updated with the current volume .
image
MVC design for this GUI will have widget-controller pair for each visual element (button, textBox, label) and one model object to set the speaker volume and to hold the current volume.
The diagram bellow shows how MVC objects interact.
image
Application Model MVC
As Smalltalk evolved new entity called 'Application Model' (AM) was added in order to shield the model and the view from presentation logic responsibilities.  AM acts as intermediate class between the model and the presentation objects (view and controller), thus, controller and view don't access the model directly and don't register to model events, instead, they access the AM and register to AM events.
Collaboration
The controller receives inputs from the user, if the input is relevant to its widget(view) pair - it command the AM as appropriate, AM perform some UI related operation, changes internal UI related state, and command the model to change, the model performs some business operation, changes its state and raise the proper event, AM respond to that event and raise the same event,  the widget(view) respond to AM event, ask relevant data from the AM and changes its display.
image_thumb21
Why the change?
We have seen that classic MVC works great with the 'Speaker Control' GUI - the problem is that real life UI will probably have use-cases that are a little more complex.
To illustrate this point, let's add another rule to 'Speaker Control' use-case: If the volume exceed 12 than the color of the text-box text should change to red. The question is - who should be responsible for this piece of presentation logic?
We can force it on the model, so it will compare the volume to 12 and raise some special event - but that will be awkward. We can extend the text-box widget, so it will compare the volume to 12 and change its own color - that sound better but still we'll rather keep the widgets generic and ignorant of any kind of logic. 
Exactly for this kind of situations the AM was invented.
The diagram bellow shows how AM handles the new role.
image
User click on the 'IncreaseVolume' button, controller command the AM to increase volume, AM delegate the command to the model, model command the speaker and raise 'DataChanged' event, AM respond and delegate the event to the widget, widget ask AM for current volume, AM ask it from the model and return the value to the widget, widget then update its display.
Now, AM start dealing with the presentation logic: AM ask for current volume from the model, it checks if the current value is bigger than 12, if it is - it raise ColorChanged event, the widget respond to that event and update it color.
Another benefit of using the AM is that it can store view related data such as the current color of the widget, which item in the list is currently selected, witch widget is currently disable etc.
What's the problem?
The problem with AM is that it's not allowed to manipulate its view directly, it cannot simply change the color of the text-box, it must raise the 'ColorChanged' even and have the widget respond to it.
Read 'Twisting the MVC Triad  and find out how MVP design pattern solve this problem.

Sunday, June 22, 2008

Patterns of Enterprise Application Architecture (PeAA) and .NET Framework

PowerPoint presentation is now available for download  - PeAA – Patterns of Enterprise Application Architecture.ppt

.NET 2.0+ typed DataSet is a combination of Table Module, Unit of Work, Table Data Gateway and Metadata Mapping design patterns.

If you are an architect that is somewhat familiar with .NET technologies - you should know just what I mean.

If you don't - you are in for a treat.

Rush over to Amazon and buy the 'Patterns of Enterprise Application Architecture' (by Martin Fowler) book. This book provides proven patterns for use when building an enterprise application.

Patterns of Enterprise Application Architecture

This book is so important for architects because it provides vocabulary about design. While reading this book you will find that you are already familiar with most of the ideas described by its patterns - your gain is that now you know there name.

Why we so desperately need this vocabulary so we should spend our money and time reading about something we already know?

Think about it,

Java developer that knows nothing about .NET can read the first sentence of this post and immediately understand what is typed DateSet in the .NET world!

Friday, June 20, 2008

.NET Remoting Events (with C# Code Sample).

  • This post contains generic code that's ready for use.
  • Full solution is available at the bottom of the post.

This post will walk you through the implementation of a simple client-server application that establishes remoting communication in two directions while using infrastructure components that extract the common remoting related tasks from the application.

image

Introduction

Establishing inter-process communication via remoting is fairly simple for applications that require one way communication. In those kind of applications, a client requires to initiate method execution on a server object, while the server object is stateless and has no way to initiate communication with the client.

Unfortunately, things get pretty messy when clients also need to listen to server events. This requirement turns the table because now the server object needs to be able to initiate method execution on the clients objects. Consequently, the server object cannot be stateless because it must hold references to the registered clients, each client object that register to server event should be MarshalByRefObject and its assembly should be referenced by the server.

This post demonstrates how server objects can be made state-full and how clients can register to server events without having to be MarshalByRefObject nor referenced by the server.

Drawbacks

Before going any further, it's important to understand that the 'remote events' feature has its drawbacks.

If the client and the server reside in different machines - the guidance is to not use remote events in cases where there are many clients. The main problem is that the server default behavior is to dispatch events synchronously, as a result the request time is increases by a magnitude and exceptions are hard to handle. Though events can be raised asynchronously, it is not recommended for reasons such as ThreadPool starvation and possible event lost. Applications that are being designed for scalability should probably use some other mechanism (such as sockets) to get notifications from the server.

What happened if client crashes without un-registering from the server event?? without special handling the server will throw exception every time it will attempt to raise the event - since the event invocation list will still contain the callback of the disconnected client (the solution will be discussed shortly).

Can clients be notified about server disconnection? Unfortunately, remoting doesn’t expose some kind of ‘server disconnection event’ which will enable the clients to be notified when server disconnect. The only way for the clients to spot server disconnection is to invoke the remote object periodically within a try-catch block, and handle the socket exception that will be thrown in case the server is disconnected.

What's left? Use remote events if the clients and the server reside on the same machine or if there are restricted amount of reliable clients. I use it in middle size intranet style applications were there are no more than 3 well known reliable clients.

Alternatives

You can read about two way communication using .NET sockets in the post - “.NET Sockets - Multiple Clients - Two Way”.

The following video will guide you through the entire process of establishing two way communication using WCF.

____________________________________________________________________

Two Way Client Server Application

Deployment View – The Applications

In the demonstrated project, a client application is deployed on multiple machines which share network with a single server machine on which a server application is deployed. The client applications initiate remote calls on the server application and resister to its events, while the sever application is unaware of the connected clients, it raises events whenever appropriate without realizing who is listening in the other side. 

image 

You can read more about deployment diagrams in the post – “UML Deployment Diagrams – Modeling the System Physical Architecture

Components View – The Assemblies

The ‘RemotingTwoWay.App.Server’ component constitutes the sever application, it includes the remotable object that is being published to the clients. The ‘RemotingTwoWay.App.Client’ component constitutes the client application. Both of them use the ‘RemotingTwoWay.Infra.RemotingTools’ component which encapsulates remoting related tasks such as publishing remote objects and retrieving proxies for remote objects.

The ‘RemotingTwoWay.App.Global’ exposes the IRemotingDistributableObject interface which the server side remoteable object and the client side proxy (generated by remoting)  implement. The client application uses the proxy in order to invoke the remoteable object from remote.

image 

You can read more about component diagrams in the post – “UML 2.0 Component Diagrams – Modeling the System Logical Architecture

Implementation

Server-Side
The Remote Object (Part of the ‘RemotingTwoWay.App.Server’ component)

RemotingDistributableObject is the server object that is being published via remoting. Once published, multiple clients can retrieve its proxy and invoke it from remote through its IRemotingDistributableObject interface. Clients can also register to its MessageRecived event and get notified whenever the server receives new message.

In case one of the clients that registered to the remote event disconnect without unregistering from the event (such as incase of a crash) - a socket exception will accrue every time the server will attempt to raise the event.  To avoid this, in case one of the callbacks in the event invocation list throws exception – we assume that the callback source is disconnected and we simply remove the “dirty” callback from the invocation list.

It might seems awkward to remove the dirty callback from the event while iterating through the invocation list but it’s safe since ‘GetInvocationList’ returns copy of the event invocation list. This scheme also works fine in case multiple clients call the ‘SendMessage’ concurrently while the event invocation list consist of “dirty” callback, in such case the dirty callback might be called more than once (causing an exception each time) and be removed from the event more than once – but this causes no real harm and obliviously better than locking the entire block.

public class RemotingDistributableObject : MarshalByRefObject, IRemotingDistributableObject
 {
     private readonly ServerImp m_imp;

     public RemotingDistributableObject(ServerImp p_imp)
     {
         this.m_imp = p_imp;
     }
     
     public void TestConnection()
     {
         
     }

     public void SendMessage(string p_mes)
     {
         m_imp.RespondToMessage(p_mes);

         Delegate[] invocationList = MessageRecived.GetInvocationList();

         foreach (MessageRecivedDel d in invocationList)
         {
             try
             {
                 d(p_mes);
             }
             catch (Exception)
             {
                 MessageRecived -= d;
                 Debug.WriteLine("Unable to raise event on Client machine " + 
                     "(client seems to be disconnected), Removing registration");
             }
         }
     }

     public event MessageRecivedDel MessageRecived;
 }
Server Terminal (Part of the ‘RemotingTwoWay.Infra.RemotingTools’  component)

The TwoWaysServerTerminal is used to publish the server object.

public class TwoWaysServerTerminal 
   {
       public static void StartListening(int port, string tcpChannelName, 
           MarshalByRefObject remoteObject, string remoteObjectUri)
       {
           TcpChannel channel = CreateTcpChannel(port, tcpChannelName);

           ChannelServices.RegisterChannel(channel, false);

           RemotingServices.Marshal(remoteObject, remoteObjectUri);
       }

       private static TcpChannel CreateTcpChannel(int port, string tcpChannelName)
       {
           BinaryServerFormatterSinkProvider serverFormatter = 
               new BinaryServerFormatterSinkProvider();
           
           serverFormatter.TypeFilterLevel = TypeFilterLevel.Full;

           BinaryClientFormatterSinkProvider clientProv = 
               new BinaryClientFormatterSinkProvider();

           Hashtable props = new Hashtable();
           props["port"] = port;
           props["name"] = tcpChannelName;

           return new TcpChannel(
               props, clientProv, serverFormatter);
       }
   }
Server Host (Part of the ‘RemotingTwoWay.App.Server’ component)

The server host creates the remote object and calls StartListening through the TwoWaysServerTerminal. As a result, the remote object is being published and from that moment on - clients can go ahead and retrieve its proxy.

int port = 1234;

RemotingDistributableObject1 remoteObject = 
    new RemotingDistributableObject1(serverImp);

// Constants.RemoteableObjectUri = "RemotingDistributableObject1"
// Constants.RemotingChannelName = "remoting-tcp"

TwoWaysServerTerminal.StartListening(
    port, Constants.RemotingChannelName, 
    remoteObject, Constants.RemoteableObjectUri);
 Both-Sides
Remotable object interface (Part of the ‘RemotingTwoWay.App.Globals’ component)

IRemotingDistributableObject is the interface which is being implemented by both server side remotable object and client side proxies, by that allowing the clients to make remote calls on the  server object in a type safe fashion.

[Serializable]
public delegate void MessageRecivedDel(string message);

public interface IRemotingDistributableObject
{
    void TestConnection();

    void SendMessage(string p_mes);

    event MessageRecivedDel MessageRecived;
}
ClientEventsWrapper (Part of the ‘RemotingTwoWay.App.Globals’ component)

As mentioned above - "each client that register to server event should be MarshalByRefObject and its assembly should be referenced by the server". To avoid this, client instantiate the ClientEventWrapper class (which reside in a separate assembly that both client and server reference) and instead of registering its own methods to the server events - it register the ClientEventWrapper object methods, than the client register to matching events on the ClientEventWrapper object and handle the server events indirectly. As a result -the server object loads the ClientEventWrapper (which is MarshalByRefObject) object instead of the client object (that is not MarshalByRefObject and doesn’t have to be referenced by the server).

public class ClientEventsWrapper : MarshalByRefObject
{
    public event MessageRecivedDel MessageRecived;

    public void MessageRecivedHandler(string message)
    {
        if (MessageRecived != null)
        {
            MessageRecived(message);
        }
    }
}
Client-Side
Client Terminal (Part of the ‘RemotingTwoWay.Infra.RemotingTools’  component)

TwoWaysClientTerminal is used to retrieve proxy for the server object.

public class TwoWaysClientTerminal
   {
       private TcpChannel m_Channel;

       public T Connect<T>(string serverName, int port, 
           string distributedObjectName, string tcpChannelName)
       {
           m_Channel = CreateTcpChannel(tcpChannelName);

           ChannelServices.RegisterChannel(m_Channel, false);

           string fullServerAddress = string.Format(
               "tcp://{0}:{1}/{2}", serverName, port, distributedObjectName);

           // Create a proxy from remote object.
           T res = (T)Activator.GetObject(typeof(T),fullServerAddress);

           return res;
       }

       private static TcpChannel CreateTcpChannel(string tcpChannelName)
       {
           BinaryServerFormatterSinkProvider serverFormatter = 
               new BinaryServerFormatterSinkProvider();
           
           serverFormatter.TypeFilterLevel = TypeFilterLevel.Full;

           BinaryClientFormatterSinkProvider clientProv = 
               new BinaryClientFormatterSinkProvider();

           Hashtable props = new Hashtable();
           props["name"] = tcpChannelName;
           props["port"] = 0;

           return new TcpChannel(props, clientProv, serverFormatter);
       }

       public void Disconnect()
       {
           if (m_Channel != null)
           {
               ChannelServices.UnregisterChannel(m_Channel);
           }
       }
   }
Client Host (Part of the ‘RemotingTwoWay.App.Client’ component)

Client host creates instance of TwoWaysClientTerminal, connects to the server and retrieve proxy for the server object.  It creates ClientEventWrapper object and register its methods to handle server proxy events,  it then register its own callbacks (that do the actual work)  to the ClientEventWrapper object events.

So when the server raises event - ClientEventWrapper callback is called, which in turn calls the client callback that handle the event as appropriate.

m_Terminal = new TwoWaysClientTerminal();
int port = 1234;

// Constants.RemoteableObjectUri = "RemotingDistributableObject1"
// Constants.RemotingChannelName = "remoting-tcp"

m_RemoteProxy = m_Terminal.Connect<IRemotingDistributableObject>(
    "localhost", port, Constants.RemoteableObjectUri, 
    Constants.RemotingChannelName);

// Register wrapper to remoting proxy event
ClientEventsWrapper clientEventsWrapper = new ClientEventsWrapper();
m_RemoteProxy.MessageRecived += clientEventsWrapper.MessageRecivedHandler;

// Register client handler to wrapper event
clientEventsWrapper.MessageRecived += MessageRecivedHandler;

m_RemoteProxy.TestConnection();

Downloads

Source Code 2005

Source Code 2008

Interesting Links

MSDN - .NET Remoting Architecture

Alex Arlievsky - Persistent .NET Events in Stateless Remoting Server

http://www.thinktecture.com/resourcearchive/net-remoting-faq/remotingusecases

http://www.informit.com/articles/article.aspx?p=102172&seqNum=6

Performance Comparison: .NET Remoting vs. ASP.NET Web Services

Thursday, June 19, 2008

One Way .NET 2.0 Remoting (with source code).

  • This post contains generic code that's ready for use.
  • The code was tested and debugged.
  • Full solution is available at the end of the post.

Preface

In this post you can find all the code that you need in order to establish remoting communication in one direction (from client to server).

While establishing one way inter process communication via remoting is fairly simple, things get pretty messy when clients also need to listen to server events.  Please refer to ".NET Remoting with Events" for detailed review and case study. 

One Way Client-Server Communication via Remoting.

In this article we will review the most simple implementation of a remoting based client-server application, in which communication flows in only one way; that is, the client is able to initiate method execution on server objects, while the server object is stateless and has no way to initiate remote calls on the client.

Server-Side
Remotable object

RemotingDistributableObject the server object that clients can remotely activate. Clients can get proxy for this object and call methods that exposed through IRemotingDistributableObject interface.

public class RemotingDistributableObject : MarshalByRefObject, IRemotingDistributableObject
{
    public void SendMessage(string p_mes)
    {
        ServerImp.Instance.RespondToMessage(p_mes);
    }
}
Server Terminal

This terminal is used to instantiated the server remotable object.

public class OneWayServerTerminal 
{
    public static void StartListening(int port)
    {
        TcpServerChannel channel = new TcpServerChannel(
            Constants.RemotingChannelName, port);

        ChannelServices.RegisterChannel(channel, false);

        WellKnownServiceTypeEntry remObj = new WellKnownServiceTypeEntry
        (
            typeof(RemotingDistributableObject),
            "RemotingDistributableObject",
            WellKnownObjectMode.SingleCall
        );

        RemotingConfiguration.RegisterWellKnownServiceType(remObj);
    }
}
Server Host (Console)

All server host has to do is to call StartListening through the server terminal. After that call - clients can retrieve proxy for the server object.

OneWayServerTerminal.StartListening(1234);

 

Both-Sides
Remotable object interface

IRemotingDistributableObject is the interface that the remotable object implements, the proxy that the client retrieves implement this interface.

public interface IRemotingDistributableObject
{
    void SendMessage(string p_mes);
}
Client Terminal

OneWayClientTerminal is used to retrieve proxy for the server object.

public class OneWayClientTerminal
{
    private TcpClientChannel m_Channel;

    public IRemotingDistributableObject Connect(string serverName, int port)
    {
        m_Channel = new TcpClientChannel(Constants.RemotingChannelName, null);

        try
        {
            ChannelServices.RegisterChannel(m_Channel, false);
        }
        catch
        {
            m_Channel = null;
            throw;
        }

        string fullServerAddress = string.Format(
            "tcp://{0}:{1}/RemotingDistributableObject", serverName, port);

        IRemotingDistributableObject videoServerTerminal = 
            (IRemotingDistributableObject)Activator.GetObject(
            typeof(IRemotingDistributableObject), fullServerAddress);

        return videoServerTerminal;            
    }

    public void Disconnect()
    {
        if (m_Channel != null)
        {
            ChannelServices.UnregisterChannel(m_Channel);
        }
    }
}
Client-Side
Client Host (Console)

Client host creates instance of OneWayClientTerminal, connects to the server and retrieve proxy for the server object. Later on, it can use the ClientTerminal object in order to disconnect from the server.

m_Terminal = new OneWayClientTerminal();
m_RemoteProxy = m_Terminal.Connect("localhost", 1234);

Sample project

Download from here

Interesting links

http://www.codeproject.com/KB/IP/cs_remoting.aspx

Saturday, June 7, 2008

Data Binding of Business Objects in Visual Studio .NET 2005/8

Introduction

This article reviews the way in which .NET Framework enables developers to data bind business objects to the UI at design time, much needed feature that is new to visual studio 2005.

It will walk you through a step by step tour, starting from the design time binding of typed DataSet's, through binding of simple data objects, to binding of complex business objects that were designed with no restrictions and no respect to UI needs.

Attached to this article is C# .2.0 sample project that shows how collection of business objects can become viewable and sortable such that data-bound controls can bind to them already in design time.

image 

Data Binding in .NET

Data binding enables visual element to link to a data source and stay in synch with it such that any changes made to the data source are reflected immediately on the visual element and vice versa.

In the .NET world, data source can be represented by typed DataSets that visual studio generates usually according to database scheme, and it can be represented by simple 'man made' objects; the latter can be humble data containers or intelligent business objects that also contain data.

Data source can be bound to UI control at design time using visual-studio designer, and it can be bound programmatically at run time through code that looks like -

textBox1.DataBindings.Add("Text", customerDataEntity, "CustomerId"); 
textBox2.DataBindings.Add("Text", customerDataEntity, "CompanyName"); 

Naturally, we will rather bind data at design time in order to avoid this kind of tedious code.

In the earlier versions of visual studio only typed DataSet could have been bound to UI control at design time, and that's only if both the DataSet and the control reside in the same project.

Fortunately, the introduction of the BindingSource component in visual studio 2005 allows us to bind UI control to a custom business class already at design time. This way, instead of binding and formatting each public property of the class through code (like shown above) - we can do it at design time using the control built-in designers. We will see how it’s can done momentarily.

Binding to 'typed DataSet's'

Since typed DataSet's are fully integrated with visual studio designer, once made, they can be immediately bound to UI controls that reside in the same project at design time. Smart controls such as DataGridView can be fully customized at design time once they are bound to typed DataSet.

Lets take a look, given a DataSet with the following schema -

image

As a result of binding the above dataset to a DataGridView, all the columns of the 'Customers' table are automatically added to the DataGridView. The DataGridView columns can then be edited at design time, using the DataGridView columns editor designer that is shown bellow.

image

Binding of simple raw data objects

Unlike typed DataSet's - raw data classes such as PersonDetails (shown below) are not inherently integrated with visual studio so we can't immediately bind then at design time to any UI control that resides in the same project. We have to work a little harder.

To start with, let's take a look at PersonDetails class -

public class PersonDetails
{
    private readonly string m_name;
    private readonly string m_address;
    private readonly string m_phone;

    public PersonDetails(string p_name, string p_address, string p_phone)
    {
        m_name = p_name;
        m_address = p_address;
        m_phone = p_phone;
    }

    public string Name
    {
        get { return m_name; }
    }

    public string Address
    {
        get { return m_address; }
    }

    public string Phone
    {
        get { return m_phone; }
    }
}

In order to bind PersonDetails to UI control at design time, we need to set up the PersonDetails class within the UI project. This is done using the 'Data Source Configuration Wizard' (from visual studio main menu - select the Data|Show Data Sources menu item).

image

Select 'Object' as the data source and click 'Next'. All the public classes that are referenced by the UI project will be listed; select the PersonDetails class, and click 'Finish'.

image

After completing the wizard, drag drop DataGridView control on the form surface, select the 'DataSource' property of the grid, you will see that the PersonDetails class appears under 'Other Data Sources' node, click on 'PersonDetails'.

image

As a result, 1) new BindingSource component called presonDetailsBindingSource that’s bound to 'PersonDetails' type is automatically added to the form, 2) presonDetailsBindingSource is assigned as the data source of DataGridView, 3) three columns are added to the DataGrdiView, one column for each property of 'PersonDetails' class.

The columns that were generated can then be edited at design time, using the DataGridView columns editor designer shown bellow.

image

In order to present collection of 'PersonDetails' objects on the grid, all we need to do is to assign the collection to presonDetailsBindingSource.

ICollection<PersonDetails> m_personDetailses
private void UpdateBindingSource()
{
  m_personDetailses = m_personsDataMapper.GetPersons(); 
  m_presonDetailsBindingSource.DataSource = m_personDetailses;
}
Updating the Display

The next step after attaching the data source to its binding source is to attach the binding source to the appropriate view/s.

grid.DataSource = m_presonDetailsBindingSource;

In order to get the grid updated with latest state of its underlying data source, we call ResetBinding on the binding source.

m_presonDetailsBindingSource.ResetBinding();

In order to get the data source updated with changes made through the grid, we call EndEdit on the binding source.

m_presonDetailsBindingSource.EndEdit();
m_personsDataMapper.Update(m_personDetailses);

Binding complex business objects

Important rule of domain model design is to ignore presentation needs when designing the business object model. Thus, business objects should be designed according to the data structure and business rules alone.

This approach makes presentation modification easy, as well as the adding of another presentation at latter stage. You can read about separating the domain (model) from the application (presenter) and presentation (view) here.

So, because business objects are domain oriented by nature - in most cases we can't bind them 'as is' to the UI. Let's take a look at business entity called CustomerDataEntity -

public class CustomerDataEntity
{
    private readonly string m_id;
    private readonly PersonDetails m_details;
    private readonly bool m_IsPreferred;
    private readonly PersonDataEntity m_Contact;
    private List<OrderDataEntity> m_orders = new List<OrderDataEntity>();

    public CustomerDataEntity(string p_id, PersonDetails p_details, 
        bool isPreferred, PersonDataEntity contact)
    {
        m_id = p_id;
        m_details = p_details;
        m_IsPreferred = isPreferred;
        m_Contact = contact;

    }

    public string ID
    {
        get { return m_id; }
    }

    public PersonDetails Details
    {
        get
        {
            return m_details;
        }
    }

    public bool IsPreferred
    {
        get { return m_IsPreferred; }
    }

    public PersonDataEntity Contact
    {
        get { return m_Contact; }
    }

    public ICollection<OrderDataEntity> Orders
    {
        get { return m_orders.AsReadOnly(); }
    }

    public void AddOrder(OrderDataEntity p_order)
    {
        m_orders.Add(p_order);
    }

    public void RemoveOrder(OrderDataEntity p_order)
    {
        m_orders.Remove(p_order);
    }
}

CustomerDataEntity exposes the details of the customer through PersonDetails object,  it exposes customer orders through collection of OrderDataEntity objects etc.

Sadly, the properties that CustomerDataEntity exposes are no good for direct binding, since only properties of primitive types can be bound directly to DataGridView columns and the like. Such being the case, it’s pretty clear that we cannot bind the CustomerDataEntity directly as we did with PresonDetails.

Let's say that we need to present list of CustomerDataEntity objects on the following UI.

image

We need to present the customers name and phone which can be retrieved through the Details property, and we need to present the number of orders which can be retrieved through the Orders property.

We want to present the customers list on the DataGridView and on the ComboBox, and we want those two to be synchronized, so if we select customer in the ComboBox - that same customer will be automatically selected in the DataGridView and vice versa.

The first step is adding some wrapper class that we call view entity. That view entity is injected with the data entity (in our case – CustomerDataEntity) and exposes properties that fit to the desired display.

public class CustomerViewEntity
{
    private readonly string m_name;
    private readonly string m_phone;
    private readonly int m_ordersAmount;

    public CustomerViewEntity(CustomerDataEntity p_customer)
    {
        m_name = p_customer.Details.Name;
        m_phone = p_customer.Details.Phone;
        m_ordersAmount = p_customer.Orders.Count;
    }

    public string Name
    {
        get { return m_name; }
    }

    public string Phone
    {
        get { return m_phone; }
    }

    public int OrdersAmount
    {
        get { return m_ordersAmount; }
    }
}

The CustomerViewEntity can be bound to the DataGridView just like we did with the PersonDetails class.

The following code shows the full sequence, starting from getting the data using the proper mapper, through creating the collection of view wrappers, to assigning it to the data source.

CustomerDataMapper mapper = new CustomerDataMapper();

ICollection<CustomerDataEntity> customerDataEntities = mapper.GetAllCustomers();

List<CustomerViewEntity> customerViewEntities = new List<CustomerViewEntity>();

foreach(CustomerDataEntity customerDataEntity in customerDataEntities)
{
    customerViewEntities.Add(new CustomerViewEntity(customerDataEntity));
}

customerViewEntityBindingSource.DataSource = customerViewEntities;

As mentioned above, after binding the CustomerViewEntity to the DataGridView, new BindingSource component is automatically added to the UI (in this case, the designer choose to call it customerViewEntityBindingSource) and assigned as the data source of the DataGridView. We can assign the same BindingSource as the data source of the ComboBox. So both DataGridView and ComboBox displays the same data from the same binding source.

As you can see, CustomerViewEntity stores the relevant data of CustomerDataEntity in its internal fields and it exposes those fields through its public properties. This means that snapshot of the customer data is presented on the grid surface, thus change to the data object will not be reflected as a result of customerViewEntityBindingSource.ResetBinding call. In addition, user will not be able to edit the CustomerDataEntity objects from the grid.

In order to make the controls synchronized with the CustomerDataEntity current data -CustomerViewEntity should be written like this -

public class CustomerSynchViewEntity
{
    private CustomerDataEntity m_customer; 
    public CustomerSynchViewEntity(CustomerDataEntity p_customer)
    {
         m_customer = p_customer;
    }

    public string Name
    {
        get
        {
            return m_customer.Details.Name;
        }
    }

    public string Phone
    {
        get
        {
            return m_customer.Details.Phone;
        }
    }

    public int OrdersAmount
    {
        get
        {
            return m_customer.Orders.Count;
        }
    }
}

This way the grid will be updated with CustomerDataEntity current data as a result of customerViewEntityBindingSource.ResetBinding call. Though, the data still cannot be edited from the grid surface since CustomerSynchViewEntity properties has only getters.

Sorting collection of business objects

In order to add sorting ability to DataGridView that is bound to collection of objects - we have to populate the BindingSource that is bound to the grid with 'special' collection that implements IBindingList and apply the proper sorting algorithm.

The collection can drive from BindingList<T> and override the proper properties and methods to apply the sorting algorithm.

Here's an example for collection that implements the basic sorting algorithm -

public class SortableList<T> : BindingList<T>, IBindingListView
{
    PropertyComparerCollection<T> sorts;

    protected override bool IsSortedCore
    {
        get { return sorts != null; }
    }
    
    protected override void RemoveSortCore()
    {
        sorts = null;
    }
    
    protected override bool SupportsSortingCore
    {
        get { return true; }
    }
    
    protected override ListSortDirection SortDirectionCore
    {
        get
        {
            return sorts == null 
                ? ListSortDirection.Ascending 
                : sorts.PrimaryDirection;
        }
    }
    
    protected override PropertyDescriptor SortPropertyCore
    {
        get
        {
            return sorts == null 
                ? null 
                : sorts.PrimaryProperty;
        }
    }

    protected override void ApplySortCore(PropertyDescriptor prop,
        ListSortDirection direction)
    {
        ListSortDescription[] arr = {
        new ListSortDescription(prop, direction)};
        ApplySort(new ListSortDescriptionCollection(arr));
    }

    public void ApplySort(ListSortDescriptionCollection sortCollection)
    {
        bool oldRaise = RaiseListChangedEvents;
        RaiseListChangedEvents = false;
        try
        {
            PropertyComparerCollection<T> tmp = 
                new PropertyComparerCollection<T>(sortCollection);
            
            List<T> items = new List<T>(this);
            
            items.Sort(tmp);
            
            int index = 0;
            foreach (T item in items)
            {
                SetItem(index++, item);
            }
            sorts = tmp;
        }
        finally
        {
            RaiseListChangedEvents = oldRaise;
            ResetBindings();
        }
    }
    
    string IBindingListView.Filter
    {
        get { throw new NotImplementedException(); }
        set { throw new NotImplementedException(); }
    }
    
    void IBindingListView.RemoveFilter()
    {
        throw new NotImplementedException();
    }
    
    ListSortDescriptionCollection IBindingListView.SortDescriptions
    {
        get { return sorts.Sorts; }
    }
    
    bool IBindingListView.SupportsAdvancedSorting
    {
        get { return true; }
    }
    
    bool IBindingListView.SupportsFiltering
    {
        get { return false; }
    }
}

public class PropertyComparerCollection<T> : IComparer<T>
{
    private readonly ListSortDescriptionCollection sorts;
    private readonly PropertyComparer<T>[] comparers;
    
    public ListSortDescriptionCollection Sorts
    {
        get { return sorts; }
    }
    
    public PropertyComparerCollection(ListSortDescriptionCollection sorts)
    {
        if (sorts == null) throw new ArgumentNullException("sorts");
        this.sorts = sorts;
        List<PropertyComparer<T>> list = new List<PropertyComparer<T>>();
        
        foreach (ListSortDescription item in sorts)
        {
            list.Add(new PropertyComparer<T>(item.PropertyDescriptor, 
                item.SortDirection == ListSortDirection.Descending));
        }
        
        comparers = list.ToArray();
    }

    public PropertyDescriptor PrimaryProperty
    {
        get
        {
            return comparers.Length == 0 
                ? null 
                :comparers[0].Property;
        }
    }
    public ListSortDirection PrimaryDirection
    {
        get
        {
            return comparers.Length == 0 
                ? ListSortDirection.Ascending 
                : comparers[0].Descending 
                ? ListSortDirection.Descending
                : ListSortDirection.Ascending;
        }
    }

    int IComparer<T>.Compare(T x, T y)
    {
        int result = 0;
        for (int i = 0; i < comparers.Length; i++)
        {
            result = comparers[i].Compare(x, y);
            if (result != 0) break;
        }
        return result;
    }

}

public class PropertyComparer<T> : IComparer<T>
{
    private readonly bool descending;
    public bool Descending
    {
        get { return descending; }
    }
    
    private readonly PropertyDescriptor property;
    public PropertyDescriptor Property 
    { 
        get { return property; } }
    
    public PropertyComparer(PropertyDescriptor property, bool descending)
    {
        if (property == null)
        {
            throw new ArgumentNullException("property");
        }
        
        this.descending = descending;
        this.property = property;
    }

    public int Compare(T x, T y)
    {
        // todo; some null cases
        int value = Comparer.Default.Compare(
            property.GetValue(x), property.GetValue(y));
        
        return descending ? -value : value;
    }
}

The following code shows the full sequence, starting from getting the data using the proper mapper, through creating sortable collection of view wrappers, to assigning it to the BindingSource component.

CustomerDataMapper mapper = new CustomerDataMapper();

ICollection<CustomerDataEntity> customerDataEntities = mapper.GetAllCustomers();

SortableList<CustomerViewEntity> customerViewEntities = 
    new SortableList<CustomerViewEntity>();

foreach(CustomerDataEntity customerDataEntity in customerDataEntities)
{
    customerViewEntities.Add(new CustomerViewEntity(customerDataEntity));
}

customerViewEntityBindingSource.DataSource = customerViewEntities;

Sample project

Download from here

Interesting links

Rockford Lhotka - Windows Forms Object Data Binding in .NET 2.0

Deborah Kurata - Object Binding Tips and Tricks

Noah Coad - Data-Binding Windows Forms with ADO.NET