In my previous post Multiple search criteria searching using Linq to SQL I talked about a way to implement multiple search criteria queries using LINQ to SQL.
Because I am doing some work using the ASP.NET MVC Framework, I looked into patterns to make a loosely coupled data layer. Ofcourse I checked out Rob Connery’s blog, he created the MVC Storefront (now Kona) the code can be found on MVC Sample Apps on Codeplex. Rob is leveraging the Repository pattern, this pattern provides dependency-free access to data of any type. I saw the screen cast where Ayende Rahien talks about ‘Filters and Pipes’.
Rob implements the filters in the MVC Storefront, I really like this approach, better than the approach in my previous post Multiple search criteria searching using Linq to SQL because it’s much cleaner, it is possible to ‘chain’ multiple criteria, but every criteria has it’s own extension method, thus following the single responsibility principle.
In my previous post in some cases I did too much in one method, I build up an IQueryable<post> for four search criteria, which breaks the Single Responsibility principle for one.

Using filters, which are extension methods that specify a filter on an IQueryable of something, makes it possible to let the calling party build up whatever they need. I know this can sound confusing, but I feel the following code example explains much better.

In my previous post, I called a few methods, and build up a IQueryable that way to satisfy every search criteria in the query.

   1:  [TestMethod]
   2:  public void Search_For_mvc_in_Title_And_Use_Paging_Test()
   3:  {
   4:   
   5:      MvcBlogDataContext repository = new MvcBlogDataContext("Data Source=.;Initial Catalog=MvcBlog;Persist Security Info=True;");
   6:   
   7:      var postsQuery = from p in repository.Posts
   8:                      select p;
   9:   
  10:      postsQuery = GetPostsQuery(postsQuery, "mvc", "", "", null);
  11:      postsQuery = GetPostsPagingQuery(postsQuery, 0, 5);
  12:   
  13:      List<Post> posts = postsQuery.ToList();
  14:   
  15:      Assert.IsNotNull(posts, "DataContext did not return posts when searching for 'mvc' in title");
  16:      Assert.AreEqual(posts.Count, 2, "DataContext did not return 2 posts when searching for 'mvc' in title");
  17:  }

Listing 1

Consuming filters
Would not it be cool if we could use a fluent interface-like way to query the data, so it will be obvious to what we want to query?
Something like the code (also in a Unit test manner like the previous post) in listing 2:

   1:  [TestMethod]
   2:  public void Search_For_mvc_in_Title_With_Paging_Test()
   3:  {
   4:      List<Post> posts = GetPosts().WithTitleLike("mvc")
   5:                                   .WhereTagsContain("")
   6:                                   .WhereBodyContains("")
   7:                                   .WithPaging(0, 5)
   8:                                   .ToList();
   9:   
  10:      Assert.IsNotNull(posts, "DataContext did not return posts when searching for 'mvc' in title");
  11:      Assert.AreEqual(posts.Count, 2, "DataContext did not return 2 posts when searching for 'mvc' in title");
  12:  }

Listing: 2

 

I think it is clear that the code in listing 2 is far more readable, than the code in listing 1. Another advantage is that it is easy to reuse every part of the query whenever it is needed.

Get all()
First I create a method that returns all Posts present in the database as an IQueryable<Post>. By the way, I am not using Dependency Injection, or Inversion of Control in this example, because it does not help in explaining the filters concept. BUT I think that when using this technique in a real world application, it is  a good thing to use IoC (StructureMap, Windsor, Ninject, Unity, whatever…).

   1:  public IQueryable<Post> GetPosts()
   2:  {
   3:      var postsQuery = from p in repository.Posts
   4:      select p;
   5:      return postsQuery;
   6:  }

Listing: 3

Extension methods
Leveraging extension methods, a .NET Framework 3.0 feature in combination with the IQueryable<T> interface, it is possible to create the filters. The class needs to be static and public, the extension methods also need to be static and public.
The first parameter specifies which type the method operates on and needs to be preceded by the ‘this’ modifier.

   1:  public static class PostFilters
   2:  {
   3:      public static IQueryable<Post> WithTitleLike(this IQueryable<Post> postsQuery,
   4:                                             string title)
   5:      {
   6:          if (!string.IsNullOrEmpty(title))
   7:              postsQuery = postsQuery.Where(p => p.Title.Contains(title));
   8:   
   9:          return postsQuery;
  10:      }
  11:   
  12:      public static IQueryable<Post> WhereTagsContain(this IQueryable<Post> postsQuery,
  13:                                                string tags)
  14:      {
  15:          if (string.IsNullOrEmpty(tags))
  16:              return postsQuery;
  17:   
  18:          return postsQuery.Where(p => p.Tags.Contains(tags));
  19:      }
  20:   
  21:      public static IQueryable<Post> WhereBodyContains(this IQueryable<Post> postsQuery,
  22:                                                 string bodyText)
  23:      {
  24:          if (!string.IsNullOrEmpty(bodyText))
  25:              return postsQuery;
  26:   
  27:          return postsQuery.Where(p => p.Body.Contains(bodyText));
  28:      }
  29:   
  30:      public static IQueryable<Post> IsCreatedOn(this IQueryable<Post> postsQuery,
  31:                                           DateTime? createdOn)
  32:      {
  33:          if (!createdOn.HasValue && createdOn.Value == DateTime.MinValue)
  34:              return postsQuery;
  35:   
  36:          return postsQuery.Where(p => p.CreatedOn.Value.Date == createdOn.Value.Date);
  37:      }
  38:   
  39:      public static IQueryable<Post> WithPaging(this IQueryable<Post> postsQuery,
  40:                                          int? startRow,
  41:                                          int? rowCount)
  42:      {
  43:          if ((!startRow.HasValue) && (!rowCount.HasValue || rowCount.Value == 0))
  44:             return  postsQuery;
  45:   
  46:          return postsQuery.Skip((int)startRow).Take((int)rowCount);
  47:      }
  48:  }

Listing: 3

In listing 3 it is obvious that every method has its own responsibility, it is easily maintainable and very readable. I think this is an elegant solution for the problem I tried to solve in my previous post, I found this better technique and want to share.

Henry Cordes
My thoughts exactly…

Currently rated 5.0 by 6 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

 Also take a look at: >> Part 2

Multiple search-criteria searching is a often encountered requirement that is not always straight forward to implement. These days we have NHibernate, Entity Framework, LBLGen, LINQ to SQL and many more.
I find that the choice for an ORM is hard, simply because there is so much to choose from.
I will not go in the choice for one or the other, but will use LINQ to SQL in this example, in my opinion if you only need a one to one mapping of your database tables to domain objects and your database does not contain a lot of tables LINQ to SQL is the way to go. LINQ to SQL is intuitive, the querying of the DataContext works as you would expect it to work and the performance is better than a lot of stored procs and T-SQL I have seen running in production at some of my clients :-).
So in this post I am going to show how to implement a search using multiple search criteria with LINQ to SQL.

The table I use in my example is a simple table called Post, it only has a few fields (see picture 1).

Pic 1: The SQL Server design of the Post table
Pic 1: SQL server design of Table ‘Post’

T-SQL
So how do we search
with T-SQL, if we want the query to return all records of the ‘Post’ table where the Title field contains the text “mvc”.
So in T-SQL, that would be:

   1:  SELECT PostId, Title, … FROM Post WHERE Title LIKE ‘%mvc%’

Listing 1: T-SQL example LIKE query

Right? In T-SQL we have to place wildcards (the ‘%’) around the search criterion we use with the LIKE operator to get the behavior that records where the Title field is “asp.net mvc framework” will be returned also, not only the records where the title field has the exact value: “mvc”.

When we execute the sql directly in the SQL Server Manager the result shows 2 rows (see picture 2).

Pic 2: Execute T-SQL in SQL Server directly
Pic 2: Execute T-SQL in SQL Server directly

LINQ to SQL model
I use LINQ to SQL to create a model (or a DataContext). The model shows the ‘entity’ you see in picture 3. As I mentioned earlier it is a one to one mapping with the SQL table from picture 1.

Pic 3: The LINQ to SQL designer shows the Post entity
Pic 3: Post entity in LINQ to SQL model

Unittest
To easily proof how many rows will be returned
I create a unittest, that instanciates the MvcBlogDataContext and does a search in the Post table. The LINQ query also looks if the Title field of the Post table contains the text “mvc”. In the test the ‘Contains’ operator is used. ‘Contains’ in LINQ to SQL works exactly the same as the LIKE with the ‘%’ wildcards in listing 1. 

   1:  [TestMethod]
   2:  public void Search_For_mvc_in_Title_Test()
   3:  {
   4:    MvcBlogDataContext repository = new MvcBlogDataContext("Data Source=.;Initial Catalog=MvcBlog;Persist Security Info=True;");
   5:    List<Post> posts = repository.Posts.Where(p => p.Title.Contains("mvc")).ToList();
   6:   
   7:    Assert.IsNotNull(posts, "DataContext did not return posts when searching for 'mvc' in title");
   8:    Assert.AreEqual(posts.Count, 2, "DataContext did not return 2 posts when searching for 'mvc' in title");
   9:  }

Listing 2: Unittest that proofs 2 records are in database

The test does an Assert on the posts object not being Null and on the number of posts in the posts object (List<Post>) being two. When we execute the test, will the test pass, or fail?

Pic 4: The unittest to proof we have 2 rows containing 'mvc' in the Title field of the Post table passed succesfully
Pic 4: Unittest to proof we have 2 rows containing 'mvc' in the Title field has passed

The test passed, the result returns two rows, so we now know two rows in the Post table contain a Title field that contains "mvc".

Make a search with multiple search criteria
Now when we have one search criterion, the LINQ to SQL query is straight forward. But in real life the requirements are in a lot of cases that you have a lot of search criteria, which can be used alone, or in combinations. So how do we go about in making a search with multiple search criteria?

   1:  [TestMethod]
   2:  public void Search_For_mvc_in_Title_And_Use_Paging_Test()
   3:  {
   4:    MvcBlogDataContext repository = new MvcBlogDataContext("Data Source=.;Initial Catalog=MvcBlog;Persist Security Info=True;");
   5:   
   6:    var postsQuery = from p in repository.Posts
   7:                     select p;
   8:   
   9:    postsQuery = GetPostsQuery(postsQuery, "mvc", "", "", null);
  10:    postsQuery = GetPostsPagingQuery(postsQuery, 0, 5);
  11:   
  12:    List<Post> posts = postsQuery.ToList();
  13:   
  14:    Assert.IsNotNull(posts, "DataContext did not return posts when searching for 'mvc' in title");
  15:    Assert.AreEqual(posts.Count, 2, "DataContext did not return 2 posts when searching for 'mvc' in title");
  16:  }

Listing 3: Unittest search with multiple search criteria and paging

Listing 3 shows a unittest that uses the MvcBlogDataContext, the by LINQ to SQL generated datacontext. Om line 6 the postsQuery object inferes it’s type (IQueryable<Post>) from the LINQ Query that selects all posts in the datacontext.
Line 9 in listing 3 calls a method GetPostsQuery that expects an IQueryable<Post> object and some other parameters (our search criteria). We pass the postQuery that selects all posts from the datacontext.

Line 10 in listing 3 does almost the same trick, but than with other parameters, the GetPostsPagingQuery extends the query with Paging criteria and returns the extended query again as an IQueryable<Post> object.

Line 12 in listing 3 executes the query by calling ToList().

Line 14 in listing 3 does an Assert on the posts object not being Null and the next line asserts the number of posts in the posts object (List<Post>) being two.

Multi search criteria LINQ to SQL query
The following listing (4) shows the method GetPostsQuery, the method that does the actual work of building the LINQ Query according the values of the search criteria. The method’s first parameter is of type IQueryable<Post>, it returns an IQueryable<Post> also. When we use IQueryable<T> it is possible to pass LINQ queries around and extend it. 
The method in listing 4 does check for every criteria (parameter) if it has a valid value. If it doesn’t, nothing happens and we move on. If a parameter (search criterion) does contain a valid value the method will extend the query by adding the criterion to the query. For nvarchar fields the Contains operator is used. Again ‘'Contains’ works exactly the same as the LIKE with the ‘%’ wildcards from listing 1.

   1:  /// <summary>
   2:  /// Gets a LINQ to SQL Query according the provided parameters
   3:  /// </summary>
   4:  /// <param name="postsQuery"></param>
   5:  /// <param name="title"></param>
   6:  /// <param name="tags"></param>
   7:  /// <param name="createdOn"></param>
   8:  /// <param name="bodyText"></param>
   9:  /// <returns></returns>
  10:  private IQueryable<Post> GetPostsQuery(IQueryable<Post> postsQuery, 
  11:                                         string title, 
  12:                                         string tags, 
  13:                                         string bodyText,
  14:                                         DateTime? createdOn)
  15:  {
  16:      if (!string.IsNullOrEmpty(title))
  17:          postsQuery = postsQuery.Where(p => p.Title.Contains(title));
  18:   
  19:      if (!string.IsNullOrEmpty(tags))
  20:          postsQuery = postsQuery.Where(p => p.Tags.Contains(tags));
  21:   
  22:      if (!string.IsNullOrEmpty(bodyText))
  23:          postsQuery = postsQuery.Where(p => p.Body.Contains(bodyText));
  24:   
  25:      if (createdOn.HasValue && createdOn.Value > DateTime.MinValue)
  26:          postsQuery = postsQuery.Where(p => p.CreatedOn.Value.Date == createdOn.Value.Date);
  27:   
  28:      return postsQuery;
  29:  }

Listing 4: IQueryable<Post> GetPostsQuery, extends and returns the IQueryable<Post> query

Listing 5 contains the method GetpostsPagingQuery. This method also extends and returns the query. LINQ to SQL provides paging with the Skip (skip all rows untill) and Take (take n number of rows) methods. And this method uses these methods to extends the query with paging capabilities.

   1:  private IQueryable<Post> GetPostsPagingQuery(IQueryable<Post> postsQuery,
   2:                                         int? startRow,
   3:                                         int? rowCount)
   4:  {
   5:      if ((startRow.HasValue) && (rowCount.HasValue && rowCount.Value > 0))
   6:          postsQuery = postsQuery.Skip((int)startRow).Take((int)rowCount);
   7:   
   8:      return postsQuery;
   9:  }

Listing 5: Adds paging to query, using Skip and Take methods

We have everything wired up, all we have to do is execute the TestMethod in listing 3. In this test we only check for the title field to contain the text “mvc”. I think the idea is quite obvious, but in this post i do not really test it. So when I run the test, it passes, the test returned the same two rows like before:

 
Pic 5: The unittest that executed the programatically created LINQ Query according the search criteria passed succesfull

With LINQ to SQL it is possible to code queries that have to search using one or more search criteria in a structured and type safe way. It is not necessary to use string concatenation using wildcards. With LINQ to SQL we can solve this problem in a more elegant way. The fact that the SQL generated by LINQ to SQL performs really well is the icing on the cake. Or are you the type of developer that likes to write stored procs that 90 % of the time are the same but only the field and tablenames vary…

Henry Cordes
My thoughts exactly…

Currently rated 4.8 by 4 people

  • Currently 4.75/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

In a recent post, I talked about a project where the requirement is to create modules that can be used in an ASP.NET webapplication and in Sharepoint 2007, where I wanted to have separations of concerns. The way I solved this is: creating ASP.NET UserControl libraries (inside their own ASP.NET Webapplication project) that we package inside Sharepoint webparts. During development we test and debug the modules in a separate ASP.NET webapplication. We use pre-build events to copy the ascx files from the UserControl libraries to this webapplication and because we set a reference to the  webapplications, the dll’s are available already. Scott Guthrie has a tutorial on his website that explains how we do this. 

In the post I said I wanted to leverage Unity as our Inversion of Control Container and I was thinking about using the WCSF, because I wanted to use the MVP design pattern.
After some prototyping, I came to the conclusion using WCSF was not practical for our purpose.  Still I wanted to use the MVP pattern, because of unit-testing and loose coupling needs. I could not use MVC, because of the Sharepoint requirements.

The Model-View-Presenter pattern is different from MVC or Model-View-Controller in the sense that with MVC the Controller is where the request comes in and the Controller is where you control (what’s in a name…) your View and what you get from the Model.
With MVP the request comes in at the View, the View than delegates it to the Presenter that will get data from the Model and returns it back to the View.

Model View Presenter pattern Pic 1.: Model View Presenter pattern

The solution I finally found to be working really good is using the MVP design pattern and Unity in the following manner.

Model View Presenter UserControl diagramPic 2.:Model View Presenter Class Diagram 

As you can see in picture 2 the Model, View and Presenter all are implementing an interface. Practicing Interface based programming sets the door wide open for leveraging an Inversion of Control container, or IoC container. In my case I am using Unity, because I am doing this project for a client who is heavily into using Microsoft tools. All Presenters are derived from the abstract class Presenter<TView>.


Pic 3.: Interfaces used in MVP diagram

Why the interfaces?
Using Interfaces for all these parts of our component makes it easy to use an IoC container. Our objects are loosely coupled and we can switch out the concrete implementations easily, because we program against the interfaces. Say we want to test the Presenter and to avoid having a dependency on a data store or some service we want to switch the Model out for an implementation that returns the same hard coded objects each time. all we have to do is create this ‘mock’ Model that implements the IZaakModel interface (on Picture 3) and we are good to go.
To make this even more appealing: if we use an IoC container we only have to change the configuration in the container to start to use this other Model…

Here a listing of the Presenter of picture 2.

   1:  using System;
   2:  using Microsoft.Practices.Unity;
   3:  using HC.Interfaces.Zaak;
   4:  using HC.Mvp;
   5:  using HC.Domain;
   6:   
   7:  namespace HC.Presenters.Zaak
   8:  {
   9:      public class ZaakDetailPresenter: Presenter<IZaakDetailsView>, IZaakDetailsPresenter
  10:      {
  11:          private Zaak CurrentZaak{ get; set;}
  12:   
  13:          [Dependency]
  14:          public IZaakService Service { get; set;}
  15:   
  16:          private IZaakModel _model;
  17:          public ZaakDetailPresenter([Dependency] IZaakModel model)
  18:          {
  19:              _model = model;
  20:              _model.CurrentZaakChanged += new EventHandler<DataEventArgs<Zaak>>(_model_CurrentZaakChanged);
  21:          }
  22:   
  23:          void _model_CurrentZaakChanged(object sender, DataEventArgs<Zaak> e)
  24:          {
  25:              CurrentZaak = e.Data;
  26:              View.ShowCurrentZaakOnView(CurrentZaak);
  27:          }
  28:   
  29:          public override void OnViewInitialized()
  30:          {
  31:              base.OnViewInitialized();
  32:          }
  33:   
  34:          public override void OnViewLoaded()
  35:          {
  36:              View.ShowCurrentZaakOnView(CurrentZaak);
  37:          }
  38:   
  39:      }
  40:  }

Listing 1: Presenter

 

Because the Presenter (in listing 1) is derived from the Presenter<TView> abstract class, it is necessary to tell the Presenter of what type its View will be. Because we  use the Interface again, all we have to do is let Unity (our IoC container) do the work to supply the concrete implementation for this Interface. On line 13 of listing 1 we see the Dependency attribute, in this case the attribute will be used by Unity to resolve the concrete implementation of the IZaakService interface for the property (Service) on which the attribute is decorated that is configured.

The Model
The Model from picture 1 implements the Interface IZaakModel, and is responsible for getting the data if the Presenter asks for it and for letting the Presenter know that it has got this data and handing it over to the Presenter.

   1:  using System;
   2:  using Microsoft.Practices.Unity;
   3:  using HC.Domain;
   4:  using HC.Mvp;
   5:  using HC.Interfaces.Zaak;
   6:   
   7:  namespace HC.Models
   8:  {
   9:      public class ZaakModel : IZaakModel
  10:      {
  11:          public event EventHandler<DataEventArgs<Zaak>> CurrentZaakChanged;
  12:   
  13:          private IZaakService _datasource;
  14:          private Zaak _CurrentZaak;
  15:   
  16:          public ZaakModel([Dependency] IZaakService datasource)
  17:          {
  18:              _datasource = datasource;
  19:          }
  20:   
  21:          #region IZaakModel Members
  22:          public void LoadCurrentZaakById(int zaakId)
  23:          {
  24:              CurrentZaak = _datasource.GetZaakById(zaakId);
  25:          }
  26:   
  27:          public Zaak CurrentZaak
  28:          {
  29:              get { return _CurrentZaak; }
  30:              set
  31:              {
  32:                  _CurrentZaak = value;
  33:                  OnCurrentZaakChanged(new DataEventArgs<Zaak>(_CurrentZaak));
  34:              }
  35:          }
  36:   
  37:          public virtual void OnCurrentZaakChanged(DataEventArgs<ZaakExtended> e)
  38:          {
  39:              if (CurrentZaakChanged != null)
  40:                  CurrentZaakChanged(this, e);
  41:          }
  42:          #endregion
  43:      }   
  44:  }

Listing 2.: The Model

In listing 2 the Model is listed, is also depending on Unity for the resolving of the concrete implementations for interfaces. It implements IZaakModel  and thus implements the LoadCurrentZaakById method and the CurrentZaak property. When the  LoadCurrentZaakById (line 22, listing 2) is called it fills the CurrentZaak property calling a method on an object that implements the IZaakService interface (the private _datasource variable that is set by the ZaakModel constructor using Unity).

When the CurrentZaak property is filled the setter (line 30, listing 2) is used and in the setter the CurrentZaakChanged event is raised. Every object that subscribes to this event will recieve the change.

In listing 1 we can see on line 20 the Presenter has attached the event and will recieve this change. On line 26 of listing 1 the ShowCurrentZaakOnView method of the View is called.

The View
In ASP.NET a request will load an aspx page, the view is where the request starts, the view than delegates responsibility to the Presenter.

   1:  using System;
   2:  using Microsoft.Practices.Unity;
   3:  using HC.Interfaces.Zaak;
   4:  using HC.Mvp;
   5:  using HC.Domain;
   6:   
   7:  namespace HC.ZaakModule
   8:  {
   9:      public partial class ZaakDetails : System.Web.UI.UserControl,IZaakDetailsView
  10:      {
  11:          IZaakDetailsPresenter _presenter;
  12:          public event EventHandler UserControlLoaded;
  13:          [Dependency]
  14:          public IZaakDetailsPresenter Presenter
  15:          {
  16:              get
  17:              {
  18:                  return _presenter;
  19:              }
  20:              set
  21:              {
  22:                  if (value == null)
  23:                      throw new ArgumentNullException("value is null");
  24:              
  25:                  _presenter = value;
  26:                  _presenter.View = this;
  27:              }
  28:          }
  29:      
  30:          protected void Page_Load(object sender, EventArgs e)
  31:          {
  32:              if (!this.IsPostBack)
  33:              {
  34:                  this._presenter.OnViewInitialized();
  35:              }
  36:              this._presenter.OnViewLoaded();
  37:          }
  38:          
  39:          #region Control Init (Unity)
  40:          protected override void OnInit(EventArgs e)
  41:          {
  42:              IUnityContainer container = Container.Instance;
  43:              _presenter = container.Resolve<IZaakDetailsPresenter>();
  44:              _presenter.View = this;
  45:              base.OnInit(e);
  46:          }
  47:          #endregion
  48:      
  49:          #region IZaakDetailsView Members
  50:          public void ShowCurrentZaakOnView(Zaak zaak)
  51:          {
  52:              DetailsAlgemeenControl.CurrentZaak = zaak;
  53:              DetailsVoortgangControl.CurrentZaak = zaak;
  54:          }
  55:          #endregion
  56:      }
  57:  }

Listing 3.: The View

On line 50 of listing 3 the OnInit method of the UserControl (our view) is listed. Inside the body of this method we can see that we instantiate a variable named container (type IUnityContainer) and put a Container.Instance in it. On the next line (line 53) we fill the private member _presenter (the private member that is used in our property Presenter) by letting the container resolve the interface  IZaakDetailsPresenter. On the next line (line 54) we tell the Presenter that it’s View is this control. We have to do this here, because the View is where the request comes in. So this is the first component of our App that is loaded. Because my requirement is to create modules that can be used in Sharepoint or in ASP.NET, I cannot use the Global.asax to resolve the concrete implementations.

The ascx, or html is very straightforward, so i am not showing it, because I feel it is in the way of what i want to tell. I hope it is clear enough without it.

The Container
So how can
the container variable that is of Type IUnityContainer, an interface, on line 52 know what concrete class to Resolve? and where does Container come from. What does Container.Instance do?
In a class called container I create a UnityContainer using the Singleton design pattern:

   1:  using System;
   2:  using Microsoft.Practices.Unity;
   3:  using HC.Models;
   4:  using HC.Interfaces.Zaak;
   5:  using HC.Services;
   6:  using HC.Presenters.Zaak;
   7:   
   8:  namespace HC.ZaakModule
   9:  {
  10:      public class Container
  11:      {
  12:   
  13:          private static IUnityContainer instance;
  14:   
  15:          private Container() { }
  16:   
  17:          public static IUnityContainer Instance
  18:          {
  19:              get
  20:              {
  21:                  if (instance == null)
  22:                  {
  23:                      instance = new UnityContainer();
  24:   
  25:                      instance.RegisterType<IZaakModel, ZaakModel>(new ContainerControlledLifetimeManager())
  26:                          .RegisterType<IZaakService, ZaakService>()
  27:                          .RegisterType<IZaakView, Zaken>()
  28:                          .RegisterType<IZaakPresenter, ZaakPresenter>()
  29:                          .RegisterType<IZaakListView, ZaakList>()
  30:                          .RegisterType<IZaakSearchPresenter, ZaakSearchPresenter>()
  31:                          .RegisterType<IZaakSearchView, ZaakSearch>()
  32:                          .RegisterType<IZaakListPresenter, ZaakListPresenter>()
  33:                          .RegisterType<IZaakDetailsView, ZaakDetails>()
  34:                          .RegisterType<IZaakDetailsPresenter, ZaakDetailPresenter>();
  35:                  }
  36:                  return instance;
  37:              }
  38:          }
  39:      }
  40:  }

Listing 4.: The Container

 

Singleton
Using the singleton design pattern
the registering of the concrete implementation to the interfaces will be done only once, as you can see in the module I am building there are more components that follow the same pattern, so using a singleton was in my opinion the way to go in this case.
I choose to use a simple version of the singleton, I make a class called container, this class has a private static variable called instance (of type IUnityContainer).
The class has a private constructor, so the class cannot be directly created. Furthermore the class has a public static property (type IUnityContainer) that can only get a single instance of a IUnityContainer, because in the getter we check if the private member called instance (type IUnityContainer) is null or has been filled already, if it is filled the instance it contains is returned, but if it is null a new UnityContainer is instantiated and using a Fluent Interface all Interfaces and their concrete implementations are registered inside it before we pass it to the instance variable, after that the instance it contains is returned.

On line 25 of listing 4 the RegisterType has a parameter and the following RegisterType methods of the fluent interface have not. With new ContainerControlledLifeManager() as a parameter into the RegisterType method we tell Unity to resolve the concrete implementation as a singleton. In the case of the Model I need it to be a singleton, because the model is the only place some state need to be held in my architecture.

Configuration file
Configuring the registration in a  configuration file is also possible, in my case I did not wanted to do it, but I can understand that in some cases that is exactly what you want.

Conclusion
Ofcourse a lot more has to be considered when using this architecture, but I hope this article helps in understanding how you can use Dependency injection or Inversion of control and the Model view Presenter pattern to create maintainable and robust applications.

Henry Cordes
My thoughts exactly…

Currently rated 4.3 by 6 people

  • Currently 4.333333/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

SDN Article on MVC Framework

Published 3/9/2009 by Henry in ASP.NET | C#

My article (in dutch) with the title: ASP.NET Webapplications finally unit-testable, or (ASP.NET webapplicaties eindelijk unit-testbaar in dutch) is been published in the 100th edition of the SDN Magazine (Software Developers Network). SDN 100th Magazine in pdf format and is available for download.

VP100100th SDN Magazine

Henry Cordes
My thoughts exactly…

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

I am in the middle of the analysis fase for the project I mentioned in the post about using WCSF for ASP.NET (and Sharepoint) Usercontrols.  I know how I am going to integrate the UserControls into SharePoint in such a way, that the controls can be used in SharePoint and in custom ASP.NET Web applications.
I am going to use the MVP pattern without the help of WCSF or CWAB, but with the help of Unity. I will post an article in more detail about this in the near future.
For now I want to share a simple ASP.NET composite control I need, to make it easier to have watermark functionality for every textbox on a page, without having to add a TextBoxWatermarkExtender for every TextBox.

The way I accomplish this is by creating a composite control with a TextBox and a TextboxWatermarkExtender on it.

The code:

   1:  using System;
   2:  using System.ComponentModel;
   3:  using System.Web.UI;
   4:  using System.Web.UI.WebControls;
   5:  using AjaxControlToolkit;
   6:   
   7:  namespace HC.Web.Controls
   8:  {
   9:   
  10:       [DefaultProperty("Text"),
  11:        ValidationProperty("Text"),
  12:        Description("TextBox with Watermark capabilities"),
  13:        ToolboxData("<{0}:WatermarkTextBox runat=server></{0}:WatermarkTextBox>")]
  14:      public class WatermarkTextBox: CompositeControl
  15:      {
  16:          #region Private members
  17:           private TextBox textBox;
  18:           private TextBoxWatermarkExtender watermarkExtender;
  19:   
  20:           private string _DefaultWatermarkText = "Watermark";
  21:          #endregion
  22:   
  23:          #region Properties
  24:           /// <summary>
  25:           /// Gets the ClientID of the textbox
  26:           /// </summary>
  27:          [Bindable(true),
  28:          Category("Behavior"),
  29:          Description("The TextBoxClientID of the WatermarkTextBox"),
  30:          DefaultValue("")]
  31:          public string TextBoxClientID
  32:           {
  33:               get
  34:               {
  35:                   EnsureChildControls();
  36:                   return textBox.ClientID;
  37:               }
  38:           }
  39:   
  40:           /// <summary>
  41:           /// Gets or sets the Text in the textbox
  42:           /// </summary>
  43:           [Bindable(true),
  44:          Category("Behavior"),
  45:          Description("The text of the textbox"),
  46:          DefaultValue("")]
  47:           public string Text
  48:           {
  49:               get
  50:               {
  51:                   EnsureChildControls();
  52:                   return textBox.Text;
  53:               }
  54:               set
  55:               {
  56:                   EnsureChildControls();
  57:                   textBox.Text = value;
  58:               }
  59:           }
  60:   
  61:           /// <summary>
  62:           /// Gets or sets the CssClass of the Textbox
  63:           /// </summary>
  64:           [Bindable(true),
  65:           Description("The css class that is used when the textbox is in it's normal state"),
  66:           Category("Appearance"),
  67:           DefaultValue("")]
  68:           public override string CssClass
  69:           {
  70:               get
  71:               {
  72:                   EnsureChildControls();
  73:                   return textBox.CssClass;
  74:               }
  75:               set
  76:               {
  77:                   EnsureChildControls();
  78:                   textBox.CssClass = value;
  79:               }
  80:           }
  81:   
  82:           /// <summary>
  83:           /// Gets or sets the CssClass for the watermark state of the Textbox
  84:           /// </summary>
  85:           [Bindable(true),
  86:            Description("The css class that is used when the textbox is in it's watermark state"),
  87:            Category("Appearance"),
  88:            DefaultValue("")]
  89:           public string WatermarkCssClass
  90:           {
  91:               get 
  92:               { 
  93:                   EnsureChildControls();
  94:                   return watermarkExtender.WatermarkCssClass;
  95:               }
  96:               set 
  97:               { 
  98:                   EnsureChildControls();
  99:                   watermarkExtender.WatermarkCssClass = value;
 100:               }
 101:           }
 102:   
 103:           /// <summary>
 104:           /// Gets or sets the Text for the watermark
 105:           /// </summary>
 106:          [Bindable(true),
 107:           Category("Appearance"), 
 108:           Description("The (watermark)text that is shown when the textbox is in it's watermark state"),
 109:           DefaultValue("")]
 110:          public string WatermarkText 
 111:          {
 112:               get 
 113:               { 
 114:                   EnsureChildControls();
 115:                   return watermarkExtender.WatermarkText;
 116:               }
 117:               set 
 118:               { 
 119:                   EnsureChildControls();
 120:                   watermarkExtender.WatermarkText = value;
 121:               }
 122:          }
 123:   
 124:           /// <summary>
 125:           /// Gets or sets DefaultWatermarkText, cannot be empty
 126:           /// </summary>
 127:          [Bindable(true),
 128:          Category("Appearance"),
 129:          Description("The default (watermark)text that is shown when the textbox is in it's watermark state, and the WatermarkText property is empty"),
 130:          DefaultValue("")]
 131:          public string DefaultWatermarkText
 132:          {
 133:              get { return _DefaultWatermarkText; }
 134:              set 
 135:              { 
 136:                  if (value.Length > 0)
 137:                      _DefaultWatermarkText = value; 
 138:              }
 139:          }
 140:          #endregion
 141:   
 142:          protected override void RecreateChildControls()
 143:          {
 144:              EnsureChildControls();
 145:          }
 146:   
 147:          protected override void CreateChildControls()
 148:          {
 149:              SetTextBoxIdIfEmpty();
 150:              this.Controls.Add(textBox);
 151:              watermarkExtender.ID = textBox.ID + "_waterMarkExtender";
 152:              watermarkExtender.TargetControlID = textBox.ID;
 153:   
 154:              if (WatermarkText == "")
 155:              {
 156:                  WatermarkText = DefaultWatermarkText;
 157:              }
 158:              this.Controls.Add(watermarkExtender);
 159:          }
 160:   
 161:          #region Worker Methods
 162:          /// <summary>
 163:          /// Fills textBox ID if empty.
 164:          /// Format: ID + '_textBox'
 165:          /// </summary>
 166:           private void SetTextBoxIdIfEmpty()
 167:          {
 168:              if (string.IsNullOrEmpty(textBox.ID))
 169:              {
 170:                  textBox.ID = this.ID + "_textBox";
 171:              }
 172:          }
 173:          #endregion
 174:        
 175:           #region C'tor
 176:           public WatermarkTextBox()
 177:           {
 178:               textBox = new TextBox();
 179:               watermarkExtender = new TextBoxWatermarkExtender();
 180:           }
 181:           #endregion
 182:   
 183:      }
 184:  }

Listing: 1

As you can see in the code in listing 1,in the override of the CreateChildControls the actual adding of the controls to the control collection of the composite container is done.
It is important to make sure the textbox has a valid ID. Than you need to set the TargetControlID of the TextboxWatermarkExtender equal to the ID of the TextBox and the WatermarkText needs to be filled.

EnsureChildControls()
When you built a composite control make sure to call EnsureChildControls, so you can be sure the controls are accesible and no object reference not set exception is thrown.
A simple but quite useful example.

Henry Cordes
My thoughts exactly…

Currently rated 4.7 by 3 people

  • Currently 4.666667/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Version Tracker.NET v 1.0 released

Published 1/26/2009 by Henry in C#
Tags:

Today I released Version Tracker.NET v 1.0. It's a tool that simplifies version management in large solutions. This release only supports C#, but who knows, if someone asks for VB.NET (or another language) to be supported by Version tracker, maybe I will do it.
It is a WPF application, I had not worked with WPF, only Silverlight. I had a lot of fun experimenting and discovering the parts of WPF I needed for this app.

Version Tracker.NET
Version Tracker.NET

I learnt about Templates, Styles, Model-View-ViewModel and on the other side: Solution files, Project files and AssemblyInfo.cs files.
It was so much fun, I am going to try to put more features in Version Tracker.NET and maybe create another tool that's useful.

Quick download links

You can install it through ClickOnce installment or simply download the install.

Click to install Version Tracker.NET v 1.0 through ClickOnce deployment                           Click to download  Version Tracker.NET v 1.0 setup

Pick the ClickOnce deployment version if you always want the latest version, ClickOnce will tell you when a new version is available, pick the setup download if you do not need the latest version as soon as it is available and these features are all you need.

This version (v 1.0) is free for download, if you want the sourcecode drop me a line, you are free to use it, but you must mention me as the original author.

My thoughts exactly...
Henry Cordes

Currently rated 4.3 by 4 people

  • Currently 4.25/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

NDepend analyses staticly

Published 1/20/2009 by Henry in C#
Tags: ,

A few months ago Patrick Smacchia a C# MVP and the author of NDepend approached me to take a look at his product: NDepend.
I must admit until than I never done anything with it.

Nevertheless, after I checked the request was really from Patrick, I started to think about it and decided to do it, because:
A.) I felt honoured to be asked;
B.) I was curious if this product could be of value to me

FEATURES
A short overview of the area's NDepend focuses on, I took the area's from NDepend's site:

Conventions, Rules, Constraints Design, analyse and enforce your code conventions, naming guidelines and coding standards
Code Structure, Design, Dependencies     Know and control the design and structure of your code base
Build comparison Design rules to avoid breaking changes, only review changed and newly added code
Metrics Report over number of lines of code, increase testability and readability, coupling, dead code, design flaws
Code Coverage In general, but more important of newly added and refactored code, also it integrates with MS Visual Studio and NCover
Build Process / CI integration NDepend is designed to integrate with: CruiseControl.NET, VSTS Build Server, Nant and many other CI or Build tools

This list already shows that NDepend is more than just a dependency tool. Sure it can help you get an insight into the dependencies of your app or code base, but it is much more than just that.
It can help you get a deep understanding of the design and structure of any code base real fast, so if you are in the consulting business like me, this tool can really help you to get up to speed fast.
Also it can help you enforce design and coding standards, not only in the case of problems, reviews or in consulting gigs, but you can integrate it into your CI an/or build process, to get your code base to live up not only to your (quality) standards, but report about them to your clients and/or users also!
Now we know how valuable this tool is in theory, let's find out how it perform's in the real world.

INSTALLATION
So I installed NDepend, installing in the case of NDepend is nothing more than copying the files onto your harddrive and you are good to go!
I really like this approach, no registry hacks, no dependencies on stuff you do not want on your system, just the 16,6 MB of files and the .NET Framework 2.0 or higher (pic. 1).

 


Picture 1: NDepend Files

When we start it up it looks quite familiair to the Visual studio user (pic. 2):

Picture 2: Ndepend start page
Picture 2: Ndepend start page

I think the UI is made with the help of DevExpress controls (http://www.devexpress.com/Products/NET/Controls/WinForms/Bars/), so the app has dockable windows like we know and love from Visual Studio and MS Office. NDepend is skinable. In this post I started out using the default skin, but from picture 9 (Dependency Graph) on I use another skin. When I load the first assembly I must admit that I experienced exactly what Scott Hanselman describes in his post about NDepend.

<QUOTE>
The first 10 minutes of NDepend is the hardest. It has to click first. There's the whole "what the hell am I looking at" process, often followed by the "screw this" declaration, followed by a quick uninstallation and a sense of "what happened."
</QUOTE>

For this post I use the Enterprise Library 4.1 and I am going to analyze the DataAccess Application Block by selecting all dll's and .pdb files in the bin directory of the application block's source folder and dragging and dropping them onto the NDepend assembly grid (pic. 3).

Picture 3: Ndepend drag and drop assemblies
Picture 3: Ndepend drag and drop assemblies

After we dropped the grid (pic. 4) shows the assemblies that we dropped onto the grid.

Picture 4: Ndepend drag and drop assemblies
Picture 4: Ndepend drag and drop assemblies

When I click on OK, NDepend starts it's magic, after a minute Internet Explorer is loaded with a report that contains all information on the project and the NDepend start page (pic. 2) is replaced with multiple dockable windows, containing multiple windows that present information about the codebase in their own way (pic. 5).

Picture 5: Ndepend First analysis
Picture 5: Ndepend First analysis

While the analyzing takes place NDepend shows what it is doing in a for Visual Studio users very familiair way.
The Visual Studio Output Window and the error list rolled into one. It looks the same and it behaves the same. The window in picture 6 shows what NDepend is doing and what the results of it's actions are.

Picture 6: Ndepend Error list
Picture 6: Ndepend Error list

NDepend calls this the Error List (familiair?). Because of the complexity that NDepend is dealing with, I think that the familairity with Visual Studio is a good thing. If you are like me, deep inside you know that static code analysis is necessary, but it can get really overwhelming. Making NDepend familair helps getting over the initial "why do I need all this?" feeling, it does not completely remove it, but it helps. In other words: IMO this approach is good .

CLASS BROWSER
As shown in picture 5 left the 'Class Browser' window is shown, again exactly like we are used to in Visual Studio, the NDepend 'Class Browser' shows a treeview with all classes and their methods, properties, interfaces and fields (pic. 7). Not exactly the same, but close enough.


Picture 7: Ndepend class Browser

CONTEXT (sensitive)
Everything in the NDepend UI is context sensitive, by that I mean wherever you select an item in a list or in a picture the other windows of NDepend show data that is relevant to the selected item.

METRICS
This window (pic. 8) puzzled me a lot at first. what am I looking at?
It is a visual way of showing the codebase, all elements are shown as grey rectangles. which are grouped into a rectangle which is the assembly or class. all methods and members are grey rectangles inside the class rectangle. The rectangles are bigger if they contain more lines of code. You can hover over them with your mouse and information (names etc.) is shown in a context sensitive way. Again, the other windows react to these changes and show data accordingly.


Picture 8: Ndepend Metrics

DEPENDENCY GRAPH
The Dependency Graph (pic. 9) window shows an image that is a visual represantation of the code base (or selected part of the code base!).


Picture 9: Ndepend Dependency Graph

Again it is context sensitive, if you select some class or member in another window, the content of the Dependency Graph changes accordingly and when you hover over a class in the Dependency Graph, the other windows react to this change.

Picture 10: Ndepend Dependency Graph context
Picture 10: Ndepend Dependency Graph context

DEPENDENCY MATRIX
The Dependency Matrix shows the coupling of the classes in  the code base. It shows exactly how many methods and fields are used between all classes.


Picture 11: Ndepend Dependency Matrix

Picture 11 shows that 74 methods of Microsoft.Practices.EnterpriseLibrary.Data are using 71 members of Microsoft.Practices.EnterpriseLibrary.Common, so green are methods and blue are members.
By right clicking on an item in the matrix a contect menu is opened where several actions can be chosen.


Picture 12: Ndepend Dependency Matrix contect menu

CQL QUERIES WINDOW
In this window (pic. 13) the CQL Queries can be selected. When selected the query is done during the analysis. The queries are grouped. NDepend comes with a lot of pre-defined queries. They are called queries for a reason, Patrick Smacchia created his own query language called CQL (Code Query Language). With this language it is possible to query code. CQL is the heart and soul of NDepend, it makes NDepend flexible and extensible. It is possible to create your own groups and CQL queries.
It goes too far for this article to go into detail, but I think it is brilliant to use a query language to analyse code.


Picture 13: Ndepend CQL Queries window

You might think: "real nice that I can write my own queries, but such a query language must be time consuming to learn", and discard this option right away, DON'T! Patrick did not only created his own query language, he also made an editor with intellisense! And it really works, it is really easy to write your own CQL query. Give it a try and you know what I am talking about.


Picture 14: Ndepend Roll your own CQL Queries

While I was working on this article, I came to appreciate NDepend more and more. I think it is a mature and well structured tool.
The integration with NCover, Reflector, Visual Studio 2005 and 2008, CruiseControl.NET, VSTS Build Server and Nant are impressive.
It also provides the possibility to choose another code editor over Visual Studio, all these integration possibilities make it very strong, because no matter what your preference is, NDepend will work with the tools you work with. 

The UI provides all functionality needed, but I hope that in the future we get a WPF based version of NDepend. The Windows forms UI and the DevExpress dockable windows provide all functionality, but in this day and age I just expect that slick look and feel.

Because NDepend focusses on static analysis only and does this very well. The use of CQL, the query language created to query code is brilliant. Every weird aspect that you need to report over in your codebase is possible through this language and it's editor with intellisense.

The way all windows show information about the code base in their own unique but comprehensive way is exactly what you would expect from a tool like this. The way all windows react in a context sensitive way to selections or changes made in other windows, gives me the feeling that this tool is created with a professional in mind and makes it a pleasure to work with NDepend.

My thoughts exactly...
Henry Cordes

Currently rated 3.7 by 3 people

  • Currently 3.666667/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Series  - Create a UserControl with Silverlight 2.0 Beta x

Part I   - Create a UserControl with Silverlight 2.0 Beta 1
Part II - Create a UserControl with SilverLight 2.0 Beta  

DependencyProperties

In my post Create a UserControl with Silverlight 2.0 Beta 1. I started creating a UserControl in Silverlight using Silverlight 2.0 Beta 1, Beta 2 is out now.
Because I want to get familair with Silverlight (WPF, Silverlight should be a subset of WPF and thus IMO a great way to get more knowledge of this technology).

In my first part of the story, I made a UserControl. I did it with the .NET knowledge I already had, but doing so, I completely forgot to RTFM.
Later I did and learned about DependencyProperties. A great other way to work with properties.

MSDN:
A property that is backed by the WPF property system is known as a dependency property.
The purpose of dependency properties is to provide a way to compute the value of a property based on the value of other inputs. These other inputs might include system properties such as themes and user preference, just-in-time property determination mechanisms such as data binding and animations/storyboards, multiple-use templates such as resources and styles, or values known through parent-child relationships with other elements in the element tree. In addition, a dependency property can be implemented to provide self-contained validation, default values, callbacks that monitor changes to other properties, and a system that can coerce property values based on potentially runtime information. Derived classes can also change some specific characteristics of an existing property by overriding dependency property metadata, rather than overriding the actual implementation of existing properties or creating new properties.

The concept is a little overwhelming at first, seeing DependencyProperty code the first time can be confusing.
In Part 1 the HC.Silverlight.TryOut.GenderChooser had the property Gender.

   1:  public GenderChoice Gender
   2:  {
   3:      get { return _Gender; }
   4:      set 
   5:      { 
   6:      _Gender = value;
   7:      SetColorAccordingToChoice();
   8:      OnGenderChosen(this, _Gender);
   9:      }
  10:  }

Listing 1

In the setter of the Gender property, the method SetColorAccordingToChoice is called, this sets the colors of the symbols in a particular way and it fires the OnGenderChosen event.
Every containing control can subscribe to this event and react to changes when it is fired.

Now, in WPF and Silverlight DependencyProperties are available, this property is a great candidate for this concept. But how does it work?
First we refactor our Property  to use GetValue in the setter and SetValue in the setter. We also add a GenderProperty of type DependencyProperty and call the static method Register on the DependencyProperty object:

   1:  public GenderChoice Gender
   2:  {
   3:     get { return (GenderChoice)GetValue(GenderProperty); }
   4:     set { SetValue(GenderProperty, value); }
   5:  }
   6:   
   7:  public static readonly DependencyProperty GenderProperty =
   8:     DependencyProperty.Register("Gender", typeof(GenderChoice), 
   9:                                           typeof(GenderChooser), 
  10:                                           new PropertyMetadata(
  11:                                           new PropertyChangedCallback(OnGenderChanged)));

Listing 2

Now we got the skeleton to use the DependencyProperty concept in the getter and setter of the property. And we also got a DependencyProperty with the name GenderProperty registered on the FrameworkElement.

Lets analyse the registering of the DependencyProperty. First we look at the signature for the public static Register method on the System.Windows.DependencyProperty class.

   1:  // Summary:
   2:  //     Registers a dependency property with the specified property name, 
   3:  //       property type, owner type, and property metadata for the property.
   4:  //
   5:  // Parameters:
   6:  //   name:
   7:  //     The name of the dependency property to register.
   8:  //
   9:  //   propertyType:
  10:  //     The type of the property.
  11:  //
  12:  //   ownerType:
  13:  //     The owner type that is registering the dependency property.
  14:  //
  15:  //   typeMetadata:
  16:  //     A property metadata instance. 
  17:  //       This can contain a System.Windows.PropertyChangedCallback
  18:  //     implementation reference.
  19:  //
  20:  // Returns:
  21:  //     A dependency property identifier that should be used to set the value of
  22:  //     a public static readonly field in your class. That identifier is then used
  23:  //     to reference the dependency property later, for operations such as setting
  24:  //     its value programmatically.
  25:  public static DependencyProperty Register(string name, 
  26:                                            Type propertyType, 
  27:                                            Type ownerType, 
  28:                                            PropertyMetadata typeMetadata);

Listing 3

The first parameter in the static Register method is name (string). Name is the name of the identifier field that you use to store the name and characteristics of the dependency property must be the Name you chose for the dependency property as part of the Register call appended by the literal string Property.
It is very important to follow the naming pattern, if you fail to designers might not report your property correctly, and certain aspects of property system style application might not behave as expected.

In our example,

  • the name of the dependency property and its CLR accessor is Gender;
  • The identifier field is GenderProperty;
  • The type of the property is GenderChoice;
  • The type that registers the dependency property is GenderChooser;
  • The PropertyMetadata is used to register the PropertyChangedCallback OnGenderChanged on the DependencyProperty, whenever the value in the property changes (is set) this callback is fired. In this callback you put the code to do your validation or any code that needs to run when the value of the property changes. 

So now we need a delegate to declare our EventHandler. The delegate OnGenderChangedEventHandler returns nothing but takes an object and a GenderChoice as parameters.
Furthermore we need a public event GenderChanged and a private static void OnGenderChanged which is the callback function that is fired when the value of the Property changes.

   1:  public delegate void OnGenderChangedEventHandler(object sender, GenderChangedEventArgs e);
   2:   
   3:  public event OnGenderChangedEventHandler GenderChanged;
   4:   
   5:  /// <summary>
   6:  /// Raises Event for DependencyProperty
   7:  /// </summary>
   8:  /// <param name="d"></param>
   9:  /// <param name="e"></param>
  10:  private static void OnGenderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  11:  {
  12:     if (d is GenderChooser)
  13:     {
  14:         ((GenderChooser)d).SetColorAccordingToChoice(e);
  15:         ((GenderChooser)d).OnGenderChosen((GenderChooser)d, 
  16:                            new GenderChangedEventArgs((GenderChoice)e.NewValue));
  17:     }
  18:  }

Listing 4

This is all the code you need to make a DependencyProperty.
But in our UserControl from Part 1 ,the GenderChooser, we need the GenderChosen event to fire as soon as the value of our Gender property changes. As we see on line 15 of Listing 4 the OnGenderChanged method must be static, because the DependencyProperty.Register method on line 8 of Listing 3 is static and it calls the callback.

Because the callback function OnGenderChanged is static, we need to cast the DependencyObject d to the right object, GenderChooser, after we check if d is of type Genderchooser ofcourse.
Next we call the methods on the calling object itself with the help of a cast (((GenderChooser)d).SetColorAccordingToChoice(e);).

As is shown on line 15 of Listing 4 the OnGenderChosen method is called, which takes an object and a GenderChangedEventArgs, with a GenderChoice as parameter in the constructor, as parameters.
This is the method that will raise the event GenderChosen, if a class is attached to the eventhandler.

So we need the following code to make the event GenderChosen to work.

   1:  // Outside the class!
   2:  public delegate void GenderChosenEventHandler(object sender, GenderChoice gender);
   3:   
   4:   
   5:  // public partial class GenderChooser : UserControl
   6:  // {
   7:   
   8:  public event GenderChosenEventHandler GenderChosen;
   9:   
  10:  private void OnGenderChosen(object sender, GenderChangedEventArgs e)
  11:  {
  12:      if (GenderChosen != null)
  13:      {
  14:          GenderChosen(sender, e.SelectedGender);
  15:      }
  16:  }

Listing 5

The GenderChosenEventHandler needs to be global, so needs to be outside the class and inside the namespace.
On line 10 (Listing 5) you see GenderChangedEventArgs, this is a class derived from EventArgs with nothing more than a TimeStamp and a GenderChoice property.
So it is easy to pass the SelectedGender in the Event.

GenderChangedEventArgs code

   1:  using System;
   2:   
   3:  namespace HC.Silverlight.TryOut
   4:  {
   5:      public class GenderChangedEventArgs: EventArgs
   6:      {
   7:          #region Properties
   8:          public DateTime Stamp { get; set; }
   9:          public GenderChoice SelectedGender { get; set; }
  10:          #endregion
  11:   
  12:          #region C'tors
  13:          public GenderChangedEventArgs(GenderChoice selectedGender)
  14:          {
  15:              Stamp = DateTime.Now;
  16:              SelectedGender = selectedGender;
  17:          }
  18:          #endregion
  19:      }
  20:  }

Listing 6

In Part I Line 36 to 55 the region 'Events' and the region 'EventHandler' can be removed! (thank you, Micheal Ashby (Microsoft) for pointing this out...).

Last but not least, the project is available and can be downloaded here.

DependencyProperties is a well thought out concept it was one of the first things designed when Microsoft started with WPF.
I cannot forget Mark Miller, I attended his session on WPF at the DevDays in Holland, he said: "WPF is designed by geniuses, but implemented by ...", I think the first part means a lot coming from Mark...

Series  - Create a UserControl with Silverlight 2.0 Beta x

Part I   - Create a UserControl with Silverlight 2.0 Beta 1
Part II - Create a UserControl with SilverLight 2.0 Beta  

Henry Cordes
My thoughts exactly...

Currently rated 4.2 by 5 people

  • Currently 4.2/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

ASP.NET MVC Preview 3 is released. You can download it from here:
http://www.microsoft.com/downloads/details.aspx?FamilyID=92F2A8F0-9243-4697-8F9A-FCF6BC9F66AB&displaylang=en

I took the following quote from ScottGu's blog which is a dutch translation!
Je kan hier een geintegreerd pakket van de ASP.NET MVC Preview 3 setup downloaden. Als je dat wil, kan je ook de ASP.NET MVC Preview 3 framework broncode en de framework unit tests hier downloaden.
Which means something along the line of:
You can download an integrated ASP.NET MVC Preview 3 setup package here.  You can also optionally download the ASP.NET MVC Preview 3 framework source code and framework unit tests here.

The way Microsoft is open about the code they write, is awsome to me.
The 'ScottGu teams' really turning the game upside down, IMHO it is so cool and insightfull to look at the way the MVC Framework team sets up the framework. The opportunity to look at their tests is another learning experience to me.
So download an learn, is what I say!

Henry Cordes
My thoughts exactly...

Currently rated 3.0 by 1 people

  • Currently 3/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Series  - Create a UserControl with Silverlight 2.0 Beta x

Part I   - Create a UserControl with Silverlight 2.0 Beta 1 (this post)
Part II - Create a UserControl with SilverLight 2.0 Beta

Wanting to know what all the hype is really about, I started to think about creating a web application with Silverlight.
Before I will create an application, my idea is to start of with a UserControl. A really simple one too. For the application I am going to maybe be building with Silverlight, I need a UI component to choose the gender of a person.
You could use two radiobuttons, make them a member of the same group and we're off. But with Silverlight we can try a more graphical approach, maybe a more intuitive control. I want to create a control that has the Male and Female Symbol that are clickable, through clicking on a symbol you select the gender.

I installed:

  • Microsoft Expression Design
  • Microsoft Expression Blend 2.5 March 2008 Preview
  • Microsoft Visual Studio 2008
  • Microsoft Silverlight Tools Beta 1 for Visual Studio 2008

First thing you learn when starting to use this technology is that you really need a designers eye on things. So if you are not a creative person, that likes designing stuff, maybe you need a designer to do it for you.
We are going to try to do the design ourselves for now.

Create Solution and projects
First I Fired up Visual Studio 2008. I created a new Silverlight Application (so it is easy to try our control out).

New Silverlight Application
Create Silverlight Application

As soon as you click OK, you are presented a choice, because Silverlight will be hosted on or inside a web page, you have to choose from the following options:

  1. Create only the Silverlight app and let Studio generate an HTML page for you to test the app with (only in bin/debug)
  2. Add a Website project to your solution
  3. Add a Web Application Project to your solution

 

How you want to host your Silverlight app?
Select hosting application type

I choose option 3. a Web Application Project. Now I got two projects inside my solution. I right click on the Page.xaml file and choose "Open in Expression Blend"

 

Open in Expression Blend
Open in MS Blend

Blend
Rightclick on the Silverlight project file and choose "Add New Item..." from the menu

Add new item to Silverlight application project in Blend
Add New Item

Select UserControl as template and give the control a name.

Give the xaml file for your UserControl a name
New Item

Rightclick in the area named: "Objects and Timeline" in the left side of Blend, on the UserControl and select Rename, give the control a name (GenderChoose), it cannot be the same as the name you gave the .xaml file (this is confusing, because the New Item dialog suggests you name the Usercontrol, but all you do is name the xaml and these names both must be unique.

Rename the UserControl in blend
Rename Control

Because the background of the LayoutRoot is white (see picture)

White background color of Usercontrol
Background white

We need to change it to transparent, we do this by selecting the LayoutRoot inside the UserControl

Select LayoutRoot Grid in Blend
Select LayoutRoot

After this,we select the little square that is on the right of the BackGround Brush setting

Change Background Brush in Blend
Background brush

In the contextmenu choose "Reset" and the background is transparent

No Brush in Bakground anymore
No brush

Background Usercontrol transparent
Background transparent

Design
Now it is time to fire up Microsoft Expression Design, it is a vector based drawing and design tool. I need to create the Male and Female symbols with it.
Click File > New and create a document with Width: 120 px and Height 140 px.
From the toolbox select an Ellipse

Select Ellipse in Blend Toolbox
Select Ellipse

Draw a circle and select a line, to draw the arrow on the upper right of the circle. Set the width of the line to 10px. You should be making something like this:

Male symbol inside Microsoft Expression Design
Male Symbol


Select all paths in your drawing, than click Object > Compound Path > Make, or use Ctrl + 8. Than again select all on your drawing

Compounded path result in MS Expression Design for the Male symbol
Compounded path

and paste into your control in Blend.

Male symbol pasted inside Blend
Path inside Blend Control

Rename the Path to MalePath. Do the same for the Female symbol (draw, make compound path, copy and paste into Blend) and rename this path into FemalePath. Give the paths a color you like, by selecting and choosing the right color in Brush option. Now we got something like this

Symbols have color
Colors added

And the result in Xaml is this:

   1:  <UserControl
   2:      xmlns="http://schemas.microsoft.com/client/2007"
   3:      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   5:      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
   6:      mc:Ignorable="d"
   7:      x:Class="HC.Silverlight.Tyout.GenderChooser"
   8:      d:DesignWidth="288" d:DesignHeight="160" x:Name="GenderChoose">
   9:   
  10:      <Grid x:Name="LayoutRoot" Height="160" Width="244" >
  11:          <Path x:Name="MalePath"    
  12:              MouseLeftButtonDown="MalePath_MouseLeftButtonDown" 
  13:              MouseEnter="MalePath_MouseEnter"    
  14:              MouseLeave="MalePath_MouseLeave"   
  15:              Stretch="Fill" StrokeThickness="10" 
  16:              StrokeLineJoin="Round" 
  17:              Stroke="#4C0E1B4B" 
  18:              Data="M71.182777,43.484818 C88.632889,57.770176 91.340874,83.323097 77.231247,
  19:                  100.56004 C63.121323,117.79601 37.536755,120.18899 20.086346,
  20:                  105.90402 C2.6360354,91.620079 -0.071950652,66.066154 14.037977,
  21:                  48.829205 C28.147804,31.592951 53.732468,29.20006 71.182777,
  22:                  43.484818 z M71.687004,42.605003 L102.30298,5.2050009 L104.313,
  23:                  34.850189 M71.437004,42.401001 L102.053,5.000001 L72.594521,8.885973" 
  24:              Height="120.23" 
  25:              HorizontalAlignment="Left" 
  26:              Margin="2.93199992179871,2.15100002288818,0,37.6189994812012" 
  27:              VerticalAlignment="Stretch" 
  28:              Width="109.313" 
  29:              d:LayoutOverrides="Width"/>
  30:          <Path x:Name="FemalePath"  
  31:              MouseLeftButtonDown="FemalePath_MouseLeftButtonDown"    
  32:              MouseEnter="FemalePath_MouseEnter"    
  33:              MouseLeave="FemalePath_MouseLeave"   
  34:              Stretch="Fill"   
  35:              StrokeThickness="10"   
  36:              StrokeLineJoin="Round"   
  37:              Stroke="#4CF502E4"   
  38:              Data="M 75.6667,46.1667C 98.2183,46.1667 116.5,64.2245 116.5,86.5C 116.5,108.775 98.2183,126.833 75.6667,
  39:                  126.833C 53.1151,126.833 34.8333,108.775 34.8333,86.5C 34.8333,64.2245 53.115,46.1667 75.6667,
  40:                  46.1667 Z M 76.5,126.5L 76.5,185.167M 103.833,159.167L 48.8333,159.167"   
  41:              HorizontalAlignment="Left"   
  42:              Margin="122.833000183105,0.166999995708466,0,10.8330001831055"   
  43:              Width="91.667"   
  44:              d:LayoutOverrides="Width"/>
  45:      </Grid>
  46:  </UserControl>

Listing 1

Now we open Visual studio again, we get the following message

File is modified dialog in Visual Studio
File modified

We select Yes to all and in the upper side of the Studio Design screen we click reload.
We open the code window for our GenderChooser class (GendserChooser.xaml.cs) and I wrote the following code:

 

   1:  namespace HC.Silverlight.Tryout
   2:  {
   3:      #region Enums
   4:      /// <summary>
   5:      /// Tells which Gender
   6:      /// </summary>
   7:      public enum GenderChoice
   8:      {
   9:          /// <summary>
  10:          /// Gender for man
  11:          /// </summary>
  12:          Male = 0,
  13:          /// <summary>
  14:          /// Gender for woman
  15:          /// </summary>
  16:          Female = 1,
  17:          /// <summary>
  18:          /// Not sure :-)
  19:          /// </summary>
  20:          Unknown = 2
  21:      }
  22:   
  23:      #endregion
  24:   
  25:      #region Delegates
  26:      /// <summary>
  27:      /// Handles GenderChosen Event
  28:      /// </summary>
  29:      /// <param name="sender"></param>
  30:      /// <param name="e"></param>
  31:      public delegate void GenderChosenEventHandler(object sender, GenderChoice gender);
  32:  #endregion
  33:   
  34:      public partial class GenderChooser : UserControl
  35:      {
  36:          #region Events
  37:          /// <summary>
  38:          /// GenderChosen
  39:          /// </summary>
  40:          public event GenderChosenEventHandler GenderChosen;
  41:          #endregion
  42:   
  43:          #region EventHandler
  44:          /// <summary>
  45:          /// Raises event, if EventHandler not null
  46:          /// </summary>
  47:          /// <param name="message"></param>
  48:          private void OnGenderChosen(object sender, GenderChoice selectedGender)
  49:          {
  50:              if (GenderChosen != null)
  51:              {
  52:                  GenderChosen(sender, selectedGender);
  53:              }
  54:          }
  55:          #endregion
  56:   
  57:   
  58:          #region Privates
  59:          private GenderChoice _Gender = GenderChoice.Unknown;
  60:          private SolidColorBrush _MaleColor = new SolidColorBrush(Color.FromArgb(255, 14, 27, 75));
  61:          private SolidColorBrush _MaleColorDisabled = new SolidColorBrush(Color.FromArgb(70, 14, 27, 75));
  62:          private SolidColorBrush _FemaleColor = new SolidColorBrush(Color.FromArgb(255, 245, 2, 228));
  63:          private SolidColorBrush _FemaleColorDisabled = new SolidColorBrush(Color.FromArgb(70, 245, 2, 228));
  64:          #endregion
  65:   
  66:          #region Properties
  67:   
  68:          #region Colors
  69:          /// <summary>
  70:          /// Gets or sets MaleColorDisabled, the color if the Male symbol is disabled
  71:          /// </summary>
  72:          public SolidColorBrush MaleColorDisabled
  73:          {
  74:              get { return _MaleColorDisabled; }
  75:              set { _MaleColorDisabled = value; }
  76:          }
  77:   
  78:          /// <summary>
  79:          ///  Gets or sets FemaleColorDisabled, the color if the Female symbol is disabled
  80:          /// </summary>
  81:          public SolidColorBrush FemaleColorDisabled
  82:          {
  83:              get { return _FemaleColorDisabled; }
  84:              set { _FemaleColorDisabled = value; }
  85:          }
  86:   
  87:          /// <summary>
  88:          /// Gets or sets MaleColor
  89:          /// </summary>
  90:          public SolidColorBrush MaleColor
  91:          {
  92:              get { return _MaleColor; }
  93:              set { _MaleColor = value; }
  94:          }
  95:   
  96:          /// <summary>
  97:          /// Gets or sets FemaleColor
  98:          /// </summary>
  99:          public SolidColorBrush FemaleColor
 100:          {
 101:              get { return _FemaleColor; }
 102:              set { _FemaleColor = value; }
 103:          }
 104:          #endregion
 105:   
 106:          /// <summary>
 107:          /// Gets or sets GenderChoice
 108:          /// </summary>
 109:          public GenderChoice Gender
 110:          {
 111:              get { return _Gender; }
 112:              set 
 113:              { 
 114:                  _Gender = value;
 115:                  SetColorAccordingToChoice();
 116:                  OnGenderChosen(this, _Gender);
 117:              }
 118:          }
 119:          #endregion
 120:   
 121:          #region C'tor
 122:          public GenderChooser()
 123:          {
 124:              // Required to initialize variables
 125:              InitializeComponent();
 126:   
 127:          }
 128:          #endregion
 129:   
 130:          #region MouseEvents
 131:          private void MalePath_MouseEnter(object sender, MouseEventArgs e)
 132:          {
 133:              MalePath.Stroke = MaleColor;
 134:          }
 135:   
 136:          private void MalePath_MouseLeave(object sender, MouseEventArgs e)
 137:          {
 138:              if (Gender == GenderChoice.Male)
 139:              {
 140:                  MalePath.Stroke = MaleColor;
 141:              }
 142:              else
 143:              {
 144:                  MalePath.Stroke = MaleColorDisabled;
 145:              }
 146:          }
 147:   
 148:          private void FemalePath_MouseEnter(object sender, MouseEventArgs e)
 149:          {
 150:              FemalePath.Stroke = FemaleColor;
 151:          }
 152:   
 153:   
 154:          private void FemalePath_MouseLeave(object sender, MouseEventArgs e)
 155:          {
 156:              if (Gender == GenderChoice.Female)
 157:              {
 158:                  FemalePath.Stroke = FemaleColor;
 159:              }
 160:              else
 161:              {
 162:                  FemalePath.Stroke = FemaleColorDisabled;
 163:              }
 164:          }
 165:   
 166:   
 167:          private void MalePath_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
 168:          {
 169:              Gender = GenderChoice.Male;
 170:          }
 171:   
 172:          private void FemalePath_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
 173:          {
 174:              Gender = GenderChoice.Female;
 175:          }
 176:   
 177:          #endregion
 178:   
 179:          #region Private Methods
 180:          /// <summary>
 181:          /// Sets color for Male and Female according to Gender chosen
 182:          /// </summary>
 183:          private void SetColorAccordingToChoice()
 184:          {
 185:              switch (Gender)
 186:              {
 187:                  case  GenderChoice.Unknown:
 188:                      MalePath.Stroke = MaleColorDisabled;
 189:                      FemalePath.Stroke = FemaleColorDisabled;
 190:                      break;
 191:                  case GenderChoice.Female:
 192:                      MalePath.Stroke = MaleColorDisabled;
 193:                      FemalePath.Stroke = FemaleColor;
 194:                      break;
 195:                  case GenderChoice.Male:
 196:                      MalePath.Stroke = MaleColor;
 197:                      FemalePath.Stroke = FemaleColorDisabled;
 198:                      break;
 199:              }
 200:          }
 201:          #endregion
 202:      }
 203:  }

 Listing 2

I use the SolidColorBrush to change the color of the symbols, (I only change the Alpha channel). I decided to make properties for the colors, that way the colors are dynamic.
An enum is used for the Gender choice, a property Gender of type GenderChoice (the enum) holds the current Gender.
In the setter for Gender the method SetColorAccordingToChoice is called in this method the current Gender is read and accordingly the richt colors are set on the symbols.

Control in startup state Control has Female selected
Control in action

The control in action, the first picture shows the control in startup state (symbols greyed out), the second picture shows the female symbol selected, under the hood the Gender is filled with GenderChoice.Female and the GenderChosen Event is fired.

All in all I think Silverlight is cool for it's purpose. It is possible to create strong graphics for your application and use them programming the language you already are used to.
The fact that not everybody is a designer is really the downside. A lot of developers will be better of creating windows or web apps using standard controls.
Ofcourse with Silverlight 2.0 standard controls are available, but the strong point of Silverlight is it's decoupling of UI from logic.

When designers are going to adopt Blend and MS Design, it could be really taking off, but until that time we have to do it ourselves.

Series  - Create a UserControl with Silverlight 2.0 Beta x

Part I   - Create a UserControl with Silverlight 2.0 Beta 1 (this post)
Part II - Create a UserControl with SilverLight 2.0 Beta

Henry Cordes
My thoughts exactly...

Currently rated 4.7 by 3 people

  • Currently 4.666667/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5