Tag Archives: WinformsMVP

A Slice Through the Layers

An index of the HomeLibrary application posts can be found here.

As I mentioned in my last Home Library post, I was eager to do a slice through the layers to test out any possible flaws or problems in my general architecture so far. To facilitate this, I fired up Balsamiq and created a View of roughly how I want one of the screens to look. The screen which manages people:
People

Note that all I want to implement here is the grid, not the whole screen. Also, I probably don’t need to explain the low fidelity nature of Balsamiq, which ensures that we don’t get too weighed down by such things as colour-selection.

The main things I want to verify in this exercise is:

  • whether I have configured Automapper correctly;
  • that my dependency injection is in order; and
  • that the data is making it from the database to the View as expected.

I created a separate branch to do this exercise, and as always with GIT, it’s very easy to make that available – LayersSlice Branch

Firstly, I created a service which will feed data to a presenter:

public class HomeLibraryService : IHomeLibraryService, IDisposable
    {
        private readonly IUnitOfWork _unitOfWork;
        private readonly IUniversalMapper _mapper;


        public HomeLibraryService(IUnitOfWork unitOfWork, IUniversalMapper mapper)
        {
            _unitOfWork = unitOfWork;
            _mapper = mapper;
        }

        public BindingList<UiModel.Models.Person> GetAllPeople()
        {
            var peopleRepository = _unitOfWork.People;
            PaginatedList<Person> peoplePaginated = null;

            peoplePaginated = peopleRepository.Paginate(0, 3);

            var uiList = new BindingList<UiModel.Models.Person>();

            _mapper.Map(peoplePaginated.AsQueryable(), uiList);

            return uiList;
        }

        public void Dispose()
        {
            //  This will be properly done in final code.
        }
    }

2 of the main things I want to verify can be ascertained right here. You can see that the parameters to the constructor are facilitating constructor injection by my dependency injection container. That is configured in my composition root, a.k.a. Program.cs:

    static class Program
    {
        private static IUnityContainer _container;

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Database.SetInitializer(new HomeLibraryInitializer());
            new HomeLibraryContext().Database.Initialize(true);

            var autoMapperBootstrapper = new MapperBootstrapper();
            autoMapperBootstrapper.Initialize();

            ConfigureIoc();

            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new PersonView());
        }

        private static void ConfigureIoc()
        {
            _container = new UnityContainer();

            _container.RegisterInstance<IMappingEngine>(AutoMapper.Mapper.Engine)
                .RegisterType<IUniversalMapper, UniversalMapper>(new TransientLifetimeManager());

            _container.RegisterType<IRepositoryProvider, RepositoryProvider>(
                new TransientLifetimeManager(),
                new InjectionMember[] {new InjectionConstructor(new RepositoryFactories())}
                );

            _container.RegisterType<IUnitOfWork, UnitOfWork>(new TransientLifetimeManager());
            _container.RegisterType<IHomeLibraryService, HomeLibraryService>(new TransientLifetimeManager());

            PresenterBinder.Factory = new UnityPresenterFactory(_container);
        }
    }

The service also contains the code which I use to map a domain object to a Ui-model (objects which are more suited and shaped to the View for use in Viewmodels). With just two lines of code I’m able to map all of the properties from the domain’s PaginatedList to the Ui’s BindingList. Thank you Jimmy Bogard!

I’ve only created one View for this demonstration as I only needed to verify the slice through the layers. What you will see in the PersonView is that I have used the PresenterBinding attribute to bind the View to the PeoplePresenter:

[PresenterBinding(typeof(PeoplePresenter))]
public partial class PersonView : MvpForm, IPersonView
{
	public PersonView()
	{
		InitializeComponent();
	}

	private void PersonView_Load(object sender, EventArgs e)
	{
		dgvPersons.AllowUserToAddRows = false;



		dgvcDelete.Image = ImageResources.delete;
		dgvcEdit.Image = ImageResources.edit;

		dgvPersons.DataSource = ViewModel.People;
	}

	public event EventHandler ViewClosing;
	public event EventHandler EditPersonClicked;
	public PersonViewModel ViewModel { get; set; }

	private void dgvPersons_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
	{
		switch (dgvPersons.Columns[e.ColumnIndex].Name)
		{
			case "dgvcIsAuthor":
				bool isAuthor;

				if (bool.TryParse(dgvPersons.Rows[e.RowIndex].Cells["dgvcIsAuthor"].Value.ToString(),
					out isAuthor))
				{
					e.Value = isAuthor ? ImageResources.tick : ImageResources.cross;
				}
				break;
		}
	}
	
	public void ReleasePresenter(IPresenter presenter)
	{
		PresenterBinder.Factory.Release(presenter);
	}

	protected override void OnClosing(CancelEventArgs e)
	{
		ViewClosing(this, EventArgs.Empty);
		base.OnClosing(e);
	}
}

WinformsMVP has 2 mechanisms for binding, that attribute and binding by convention. The reason I can’t use convention in my project is because my presenters will be located in a separate project which does not conform to the convention used by WinformsMVP to search for presenters. And that’s okay. It was a design choice I made. But if people prefer to bind by convention and to organise their projects in such a way that it conforms to that convention, then that’s okay too.

When the app is fired up, the following window loads:
PersonView

It’s not much to look at now, but this is just “proof of concept” time. The data is there and all is well for the plumbing, from top to bottom in the stack.

Note that a lot of the code in this post (in the branch referred above) will not look the same as I progress the project further. I have already moved forward and started putting in place the bootstrapping code in earnest.

Look out for a post in the near future which will talk about the query handling aspects of my architecture by virtue of the Mediator Pattern. Got to keep those presenters clean!

Home Library

An index of the HomeLibrary application posts can be found here.

This year I have set a little project for myself. A bit of background first. Last year I released a project called WinformsMVP which is an MVP framework for the Winforms platform. The example code that I provided with the source was quite trivial. Previous to that, in my first year as a programmer, I created a Winforms application which assisted my study for the Winforms MCTS certification. I thought it would be nice to take that application and re-implement it using the WinformsMVP framework. I will also take the opportunity to use up-to-date tools like Entity Framework 6 (code first) and perhaps a few other little utilities which I have come across in my travels.

I have already made a start on the application which I am going to call Home Library. It is basically an application which individuals can use to track their lendings of books to others. I’ve lost many books over the years where they have not been returned and I did not track who I lent it to. This application helped me address that and it was fun to make.

The code for this project is available at this GitHub repository. I plan to tag the code at various milestones and the tag for the current state of the code is called DataAccessAndDomain_1. Mind you, that doesn’t mean I won’t go back and re-factor code. But I think tagging it at various milestones will be helpful as I make blog posts with regards to the project, as it progresses.

I don’t have much in the way of Business Analysis skills; and in any case, I am the client and subject-matter expert here. So I got to work and created the domain classes which I used to generate my database. The database schema looks like this (diagram generated using the Entity Framework Power Tools): Home Library Schema

To give you an idea of the domain classes, here are a couple which I have created:

public class Book
{
	public int Id { get; set; }
	public string Title { get; set; }
	public Edition Edition { get; set; }
	public Publisher Publisher { get; set; }
	public int PublisherId { get; set; }
	public BookType TypeOfBook { get; set; }

	public virtual ICollection<Person> Authors { get; set; }
	public virtual ICollection<Comment> Comments { get; set; }
	public virtual ICollection<BookCover> Covers { get; set; }
	public virtual ICollection<Lending> Lendings { get; set; }
}
public class Person
{
	public int Id { get; set; }
	public string Email { get; set; }
	public bool IsAuthor { get; set; }
	public string FirstName { get; set; }
	public string LastName { get; set; }
	public string Sobriquet { get; set; }

	public virtual ICollection<Lending> Lendings { get; set; }
	public virtual ICollection<Book> Books { get; set; }
}

Those classes are in a separate project called HomeLibrary.Model.
You can see in the book class I have created a couple of enums. As Entity Framework 6 supports enums, it made sense to use them for abstractions which represented a finite number of options. The BookType enum looks like this:

public enum BookType
{
	TextBook = 0,
	Novel = 1
};

For the classes which will do the actual querying, I created a separate project called HomeLibrary.Model.EF. The HomeLibraryContext (which inherits from DbContext) is as follows:

public class HomeLibraryContext : DbContext
{
    //  DbSets go here
    public DbSet<Book> Books { get; set; }
    public DbSet<BookCover> BookCovers { get; set; }
    public DbSet<Comment> Comments { get; set; }
    public DbSet<Lending> Lendings { get; set; }
    public DbSet<Person> People { get; set; }
    public DbSet<Publisher> Publishers { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        //  set up the Publisher's table
        modelBuilder.Entity<Publisher>().HasKey(p => p.Id);
        modelBuilder.Entity<Publisher>().Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        modelBuilder.Entity<Publisher>().Property(p => p.Name).IsRequired().IsVariableLength();
            
        //  set up the People table
        modelBuilder.Entity<Person>().HasKey(p => p.Id);
        modelBuilder.Entity<Person>().Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        modelBuilder.Entity<Person>().Property(p => p.Email).IsRequired().IsVariableLength();
        modelBuilder.Entity<Person>().Property(p => p.FirstName).IsRequired().IsVariableLength();
        modelBuilder.Entity<Person>().Property(p => p.LastName).IsRequired().IsVariableLength();
        modelBuilder.Entity<Person>().Property(p => p.Sobriquet).IsOptional().IsVariableLength();

        //  set up the Comment table
        modelBuilder.Entity<Comment>().HasKey(p => p.Id);
        modelBuilder.Entity<Comment>().Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        modelBuilder.Entity<Comment>().Property(c => c.CommentText).IsRequired().IsVariableLength();

        //  set up the Book table
        modelBuilder.Entity<Book>().HasKey(p => p.Id);
        modelBuilder.Entity<Book>().Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        modelBuilder.Entity<Book>().Property(c => c.Title).IsRequired().IsVariableLength();

        modelBuilder.Entity<BookCover>().HasKey(p => p.Id);
        modelBuilder.Entity<BookCover>().Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

        modelBuilder.Entity<Lending>().HasKey(p => p.Id);
        modelBuilder.Entity<Lending>().Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);


        base.OnModelCreating(modelBuilder);
    }
}

You can see that I have opted for using the Fluent API for setting up the various tables rather than the Attribute-based API. Otherwise, it is a very straightforward context.

I faced an interesting scenario with seeding which I will leave for a separate blog post. The upshot of it was that I elected to do the database creation and seeding using the original EF Code First method of inheriting from a class which implements IDatabaseInitializer. As I wanted to drop and re-create the database each time I ran the application during development, I opted to inherit from DropCreateDatabaseAlways. The HomeLibraryInitializer looks like:

public class HomeLibraryInitializer : DropCreateDatabaseAlways<HomeLibraryContext>
{
    protected override void Seed(HomeLibraryContext context)
    {
        new List<Person> { new Person { FirstName = "Terry", LastName = "Halpin", Email = "hi", IsAuthor = false},
            new Person { FirstName = "Alan", LastName = "Turing", Email = "hi", IsAuthor = false }
            , }.ForEach(p => context.People.Add(p));

        context.SaveChanges();

        base.Seed(context);
    }
}

Stay tuned for future posts!