Entries Tagged 'Hobby Projects' ↓

YaYAML: Yet another YAML parser

I don’t want to make much ceremony around this, but I thought I’d mention it incase anybody else is interested.

As a part of a project I’m working on I needed a simple file to store some data in, and I didn’t want it to be XML (for no reason other than the verbosity). I could have used my own format, but instead I’ve gone for YAML. If you’ve worked with Ruby on Rails at all, then you’ll be familiar with YAML. It’s a human readable (and writable) text format.

Of course, I still needed to be able to parse my YAML document. There was a project announced 2 years ago to create a .Net parser, but like many things, it seems very much abandoned. So, after my recent adventure with OMeta#, I thought I’d hack on this too.

Introducing YaYAML: Yet another YAML parser.

Don’t get your hopes up, I’ve only implemented exactly what I needed out of the spec, which is very little indeed. However, it’s something I will carry on with when time permits. So what can you parse with YaYAML? Only documents containing a single flat sequence or mapping. No nesting, no multiple documents in a file, no variables.

It’s possible to parse these two example files:

- a list
- of text
- strings
a: mapping
of: various
key: and
value: pairs

That’s it!

You can find the source in my YaYAML github repository.

Update:
I’ve since added support for sequences of maps, so this is supported too:

- name: James
  age: 23
- name: Peter
  age: 34

SharpDiff - Diff Parsing in .NET

About SharpDiff

SharpDiff is a library for parsing the output of various diffing tools. It’s primary purpose is to reduce the time spent by SCM UI developers in handing diff output.

Why SharpDiff

I’ve got a few tools in mind that require parsing of diff files. I figure it’s a pretty common thing for SCM UI developers to have to do, so I thought i’d put it out for others to use.

Parsing your first diff

The implementation is not concrete yet, but the current (easiest) way to parse a diff file is as follows.


string diffContent = File.ReadAllText("MyDiffFile.diff");

Diff diff = Diff.CreateFrom(diffContent);

From there you have a compiled version of your diff document. Intellisense will be your friend here, but basically you have a Chunks collection, and a Files collection.

The Wikipedia article on Diffs is worth a read if you’re interested. In short though, chunks are formed as a chunk header containing the affected lines, and the lines themselves.


@@ -1,3 +1,6 @@
This is a small text file
+that I quite like,
 with a few lines of text
-inside, nothing much.

The chunk header is @@ -1,3 +1,6 @@. The -1,3 describes the affected lines in the original file, the first number (ignoring the minus) is the start line, and the second number is the total of context lines plus subtraction lines. The second range (+1,6) is in the new file, and that starts on the first line, and has six affected lines; in this case it’s all the context lines plus all addition lines.

All the other lines are the actual changes themselves. A line prefixed with a + is an addition line, a line prefixed with a - is a subtraction line, and lines prefixed with a space are context lines. Context lines are used for aligning the changes in the document. They’re also useful for determining if the document has changed since the diff was created.

In the context of SharpDiff, your Chunks collection contains an instance of a Chunk for every part in the diff that resembles the above. Each chunk has the range info for the original and new file, and a Lines collection of each line.

Early Days

WARNING: SharpDiff is still in early development. I wouldn’t recommend using it in production code yet, as the parser is severely limited, and there’s next to no error handling.

The biggest flaw is that it only supports the standard git-diff output, and doesn’t handle many special circumstances.

It does support:

  • Standard git-diff header
  • Index extended header
  • Chunk header
  • Chunk lines (added, removed, and contextual)
  • No newline at end of file
  • Multiple chunks per diff
  • Multiple diff per input string

It doesn’t support:

  • Other extended headers
  • Formats other than git-diff

Example

As quick example of what you could use this library for, here’s a screenshot of a git-diff application:

Get Involved

You can find the source on my github account, in the sharpdiff repository.

If you’re interested in helping with SharpDiff, then let me know. All comments, suggestions, and contributions are welcome. Feel free to contact me either through github, or my e-mail.

Brace Matching and your Language Service

I’ve been meaning to write up some of my experiences developing for Visual Studio while I’ve been working on BooLangStudio, but I can never seem to find the time; either that, or when I can I’m not confident enough in what I’m doing to put it out here as a valid resource.

I’ll start small, here’s a quick guide to how I’ve implemented brace matching using the managed Visual Studio extensibility SDK.

What exactly is brace matching? Brace matching is where paired characters are highlighted when one or the other is selected in the editor.

There are a couple of things you need to consider when you implement brace matching.

Firstly, there are different types of braces that can be matched (depending on your language). Taking C# as an example, the brace matching works with parentheses (()), box brackets ([]), braces ({}), and chevrons (<>). These all need to be paired independently, as to avoid matching an open parenthesis with a closing brace.

Secondly, the matching has to work bi-directionally. The user can place their caret at either side of the bracket pair, and the highlighting should know where both sides are regardless.

LanguageService implementation

A lot of the legwork of implementing a language in Visual Studio is done in the LanguageService, and brace matching is no exception. You should already have a ParseSource method in your LanguageService; this is where we’re going to work.

The ParseSource method has a ParseRequest parameter, which exposes a Reason property. When this property is set to MatchBraces, that’s when we need to do our processing.

public override AuthoringScope ParseSource(ParseRequest request)
{
  if (request.Reason == ParseReason.MatchBraces)
  {
    // match braces here
  }
}

What needs to be done is pretty simple: Parse the open document and find the partner to the brace that the caret is on.

In BooLangStudio I’ve implemented this in the following fashion:

  1. Run the document through a BracketPairFinder, which creates a list of bracket pairs in the document
  2. Get the index of the caret (baring in mind you have to translate between the Request’s Line and Column, and an actual string index)
  3. Find the pair that the caret is positioned at
  4. Get the opposite bracket from the pair
  5. Get the Line and Column of the opposite bracket

It’s upto you how you implement the above steps, as long as you end up with the opposite bracket to the one you started with. I’ll illustrate using the BooLangStudio source.

public override AuthoringScope ParseSource(ParseRequest request)
{
  if (request.Reason == ParseReason.MatchBraces)
  {
    // find all pairs
    var bracketFinder = new BracketPairFinder();
    var bracketPairs = bracketFinder.FindPairs(request.Text);

    // get index of caret from source text
    Source source = languageService.GetSource(request.View);
    int indexOfCaret = source.GetPositionOfLineIndex(request.Line, request.Col);

    // find the partner to the bracket at the caret
    int? partner = bracketPairs.FindPartnerIndex(indexOfCaret);

    if (partner != null)
    {
      // tell Visual Studio about the pair
    }
  }
}

The Source class has a helpful GetPositionOfLineIndex method, which translates between a Line and Column to a single string index. Very handy!

Once you’ve got your indices, we need to inform Visual Studio of our findings. You do that by setting the request.Sink.FoundMatchingBrace to true, then calling the MatchPair method on the Sink. You need to pass two TextSpan instances to the MatchPair method; the first is the left brace, and the second the right.

public override AuthoringScope ParseSource(ParseRequest request)
{
  if (request.Reason == ParseReason.MatchBraces)
  {

    ...

    if (partner != null)
    {
      // tell Visual Studio about the pair
      request.Sink.FoundMatchingBrace = true;

      int nextLine, nextCol;

      source.GetLineIndexOfPosition(partner.Value, out nextLine, out nextCol);

      request.Sink.MatchPair(
        new TextSpan
        {
          iStartLine = request.Line,
          iEndLine = request.Line,
          iStartIndex = request.Col,
          iEndIndex = request.Col
        },
        new TextSpan
        {
          iStartLine = nextLine,
          iEndLine = nextLine,
          iStartIndex = nextCol,
          iEndIndex = nextCol + 1
        }, 0);
    }

    return new AuthoringScope(); // replace with your implementation
  }
}

The Source class has another helpful method: GetLineIndexOfPosition method, which translates back to Line and Column from a single string index.

Finally, just return an empty AuthoringScope, as it isn’t used as part of this parse request.

That’s it! You should have now successfully implemented brace matching. You may need to tweak the TextSpan indexes depending on your parser implementation, but it shouldn’t be far wrong.

BooLangStudio implementation

If you’re interested in seeing how I handle the brace parsing, I may cover that in a future post. However, you can find all the source in my github BooLangStudio fork. Some interesting one’s in particular are:

Introducing Fluent NHibernate

A couple of people have already covered this already, specifically Bobby Johnson, Matt Hinze, and Zachariah Young. I figure I should say something on it anyway.

I’ve adopted a project from Jeremy Miller that I think has the potential to be a really useful tool. It’s called Fluent NHibernate, and it’s primarily a fluent API for mapping classes with NHibernate.

We’re all well aware how awesome NHibernate is, but I think we all also have a bit of a dislike for the amount of XML you need to write to get your classes mapped; not only that, but also how the mappings are distinctly separate from the rest of your application. They’re often neglected and untested. One of the core tenets of the project is that we need a more succinct, readable, and testable way of writing your mappings.

The API

Take the following simple hbm file:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
    namespace="Eg" assembly="Eg">

    <class name="Customer" table="Customers">
        <id name="ID">
            <generator class="identity" />
        </id>

        <property name="Name" />
        <property name="Credit" />

        <bag name="Products" table="Products">
            <key column="CustomerID"/>
            <one-to-many class="Eg.Product, Eg"/>
        </bag>

        <component name="Address" class="Eg.Address, Eg">
            <property name="AddressLine1" />
            <property name="AddressLine2" />
            <property name="CityName" />
            <property name="CountryName" />
        </component>
    </class>
</hibernate-mapping>

Then compare it to the same mapping, created using the fluent API:

public CustomerMap : ClassMap<Customer>
{
  public CustomerMap()
  {
    Id(x => x.ID);
    Map(x => x.Name);
    Map(x => x.Credit);
    HasMany<Product>(x => x.Products)
      .AsBag();
    Component<Address>(x => x.Address, m =>
    {
        m.Map(x => x.AddressLine1);
        m.Map(x => x.AddressLine2);
        m.Map(x => x.CityName);
        m.Map(x => x.CountryName);
    });
  }
}

Firstly, you’ll note that there is a marginal reduction in lines of code, but that’s not what we’re particularly striving for. Instead we’re intent on reducing the verbosity and noise of the code. This manifests itself in a convention over configuration design for the API, where we choose the most common setups and use those as the default. For example with the id element in the hbm file, you’re required to specify what the generator type is; however, in our fluent API we check the type of your identity property and decide what generator we should use. Int’s and longs default to identity, while GUIDs use the guid.comb generator. You can change these explicitly, but when you are using the default, it greatly reduces the verbosity of your mapping.

Testability

Another one of our goals is to make your mappings more robust. I imagine most people have had the problem where you’ve renamed a property and not updated the mapping file; due to there being no compile time validation, the only way to catch these mistakes are at run time (hopefully you had tests to cover that!). With the way our API is designed, you use the actual properties on your classes to create the mapping, so there’s nothing to forget. If you rename a property, your IDE will either rename the property in the mapping, or fail at compilation.

We also want to help you verify that your mappings are set up properly, not just syntactically valid. So to make your integration tests a bit easier, we’re providing an API for testing your mappings.

[Test]
public void VerifyCustomerSaves()
{
    new PersistenceSpecification<Customer>()
        .CheckProperty(x => x.Name, "James Gregory")
        .CheckProperty(x => x.Age, 22)
        .VerifyTheMappings();
}

Behind the scenes the PersistenceSpecification creates an instance of your entity, then populates it with the values you specify through the CheckProperty method. This entity is then saved to the database, then reloaded through a separate connection. The returned entity is then compared to the one originally saved, and any differences fail the test. It’s a fairly standard integration test, except we’ve taken the time to write all the wiring up that needs to be done, so you don’t have to.

The Framework

We’re working towards our first official release, which will have a fairly solid implementation of the API. Once that’s out in the wild, we’re going to focus on our Framework.

Our framework is a layer that sits on-top of the API to provide an even better experience. We’re looking to integrate with your favorite container, which will reduce the code you need to write to integrate NHibernate into your system. Then we’re going to tackle extensible conventions, which will allow you to specify your own implied conventions for your application. For example, if you’re always going to call your identifier “ID”, then why should you have to specify it every time? You shouldn’t!

Development is progressing at a nice pace, and I expect we’ll be able to get our first release out within the next few weeks. The testing API hasn’t been kept quite as up to date as the main API, but we’re working on that too. It’s open-source, so suggestions and patches are welcome.

Latest on BooLangStudio

It’s been a long time since I’ve written anything about BooLangStudio. Let me assure you that the development is still very much underway, and we’re steadily working towards our first release.

To fill you in a bit on what’s been going on. Jeffery Olson has completely rewritten the syntax highlighting to use the more flexible Boo.Pegs lexer, which allows us to overcome some of the obstacles we were facing with the traditional Boo lexer. There were limitations to what we could do with the traditional lexer, without modifying the Boo source. This was leading us down a road we weren’t keen on, one of maintaining a fork of the Boo source that contained our specific changes. With the move to the Boo.Pegs lexer, we’re free of this scenario!

Justin Chase has been tackling various issues all over the place. Several related to the build process, specifically how the Boo binaries are located on your machine, which has been a bit of a problem when there’s multiple developers working on a project whom both have Boo installed in a different location. He’s also been spiffing up the interface by adding some much needed icons to the projects.

Torkel Ödegaard has been working various issues throughout the project. He’s created a properties dialog for the project which allows you to alter the usual settings for your project, assembly name, default namespace etc… He also managed to get debugging working, which is awesome.

Then there’s me, I’ve been working on the intellisense capabilities. We’ve had intellisense support from day one, but it’s never been very extensive. For a long time it only worked on the current file you had open.

The entire solution is now processed behind-the-scenes to provide intellisense. Import statements are now recognised and imported types appear in the local scope intellisense. Any assemblies or projects that are referenced have their top-level types and namespaces included in the intellisense too.

Additionally I’ve been working on improving the method suggestion logic, which was initially very flakey. It boils down to being able to transform the current line into the desired type, which can be difficult in certain cases (StringBuilder().Append("Hello world").ToString(). for example).

I believe that about covers what we’ve been upto lately. Our biggest problem currently is that most of these features are implemented in separate branches, and haven’t yet been merged into our central repository. We’re working on this, and I reckon once we’ve done that we’ll be looking at doing a release.

Boo Visual Studio plug-in: 1% complete

What do we want? A Boo plug-in for Visual Studio. When do we want it? Sooner, rather than later.

The initial aim of this plug-in is to provide a “good enough” experience when using Boo files within other projects. I’m not currently focussing on doing full-scale development with Boo; so the target is DSLs and Binsor. There won’t be any assemblies created, or anything else that would affect your project. The only difference between how you work now would be that you could write Boo using Visual Studio, with syntax highlighting and intellisense.

That’s for the initial version anyway.

I’ve found that creating a plugin for Visual Studio isn’t that difficult, in-fact that’s an understatement, it’s stupidly easy. Most of the plugin architecture is successfully created using the project wizard, so there’s very little I needed to do from that point of view. The tricky part is getting Boo and Visual Studio to communicate.

I started by spending some time looking at the IronPython Studio implementation, the Boo implementation, abstract syntax trees, antlr, and after getting my head around what I needed to do, I set out on my adventure.

So what’s the result? A very basic (and flakey) implementation of both syntax highlighting and intellisense.

The highlighter isn’t perfect yet. It suffers from slowdown when you’re writing an unclosed string, and it can’t handle multi-line statements yet (think comment blocks).

The intellisense is pretty basic, it allows namespace navigation, and type methods, but there isn’t much in the way of constraints (you can see instance methods against types, for example).

There’s a lot of work to be done, but it’s fun and interesting.

Targets

In the near future I’d like to get the following done:

  • Make intellisense work with everything in the local scope
  • Make intellisense parse import statements
  • Make syntax-highlighting correctly handle multi-line blocks
  • Make syntax-highlighting highlight types (like C# does)

Then at some point tackle these:

  • Get Resharper involved
  • Refactoring support

Hopefully I’ll progress on these and report back in a future post.

Code

The code is poor, it’s a mess and probably all wrong; however, you can get it in the usual place. However, I haven’t provided a direct download because it isn’t really in a state to be distributed yet.

The source is accessible from Subversion at: http://jagregory.googlecode.com/svn/trunk/BooPlugin/ (using user jagregory-read-only)

Plugin baby steps

Making a Visual Studio 2008 plugin isn’t as hard as it sounds.

Making one that works is a bit more difficult.

Syntax highlighting is fairly straight forward, just run a tokenizer over the text and colour code each token appropriately. It’s the code sense that is causing me to go slightly mad. To determine what methods need to be listed when the intellisesne pops up, you need to parse the code that’s in the document, then resolve any classes and references in there to build up a collection of methods to display. It gets more tricky when the document isn’t valid, because you can’t compile it. That’s where I am now, I need to figure out some way of partially compiling the document, or maybe using an AST walker.

Futility: Transforming entities into DTOs

I just posted about how if you’re looking for a solution to a problem that hasn’t already been solved, then you’re probably doing something wrong. Well this is my case of it.

I quite dislike mapping DTOs to entities, it’s a pain, but mostly tedious and tiresome rather than difficult. I decided to try to ease things by creating a library that would resolve entity instances to their DTO counterparts.

My requirements were few but I was determined not to violate any of them.

  1. Refactoring friendly. No strings for property names, changing names should give compiler errors.
  2. Must simplify code.
  3. Must improve maintainability.

First attempt: Explicit mapping

var mapper = new DtoMapper<Customer, CustomerDto>();

mapper.Pair(mapper.Entity.Name, mapper.Dto.CustomerName);
mapper.Pair(mapper.Entity.Address, mapper.Dto.CustomerAddress);

// ... elsewhere ...

CustomerDto dto = mapper.Transform(customer);

With a clever bit of DynamicProxy usage, this implementation successfully mapped properties on an entity to a DTO. I believed it was reasonably clear, but having to use mapper.Entity was a bit obtuse. Dealing with properties on instances without an instance is tricky, especially if you want to avoid using strings.

The explicit mapping is very refactoring friendly. I could rename a property without breaking the mapping, so requirement 1 was satisfied.

var dto = new CustomerDto();

dto.CustomerName = customer.Name;
dto.CustomerAddress = customer.Address;

return dto;

As the above code demonstrates, this implementation isn’t actually any simpler than just doing simple assignments, it’s in-fact more complicated because of the overhead of understanding what the mapper is. This simple assignment method is also refactoring friendly.

So with requirement 2 failed, and requirement 3 no different to doing it manually, it was time to move on.

Second attempt: Implicit mapping

var mapper = new DtoMapper();

mapper.CreateImplicitMap<Customer, CustomerDto>();

// ... elsewhere ...

CustomerDto dto = mapper.Transform(customer);

This is my favorite implementation, it’s clean and smart; however, it’s also useless.

It did the same as the first example, but implicitly mapped any properties that have the same name together. This is fine, but it would ignore anything that don’t have the same names. I could’ve implemented some logic for guessing names, but that would just be asking for trouble.

Tragically this implementation wasn’t that refactoring friendly; you can rename properties, but it would silently stop mapping them unless you renamed it’s partner too. That’s pretty dangerous stuff. Requirement 1 failed.

It does produce less code than the first implementation, and the simple assignment method, so 2 and 3 are covered.

Third attempt: Attributes

public class CustomerDto
{
	[DtoPartner(typeof(Customer), "Name")]
	public string CustomerName { get; set; }

	[DtoPartner(typeof(Customer), "Address")]
	public string CustomerAddress { get; set; }
}

I could live with this implementation, it’s not as clean as the implicit method, but it is still quite clear.

Unfortunately, it fails in the refactoring test. You can’t rename a property on Customer without it breaking the mapping, because the property names are strings. Requirement 1 failed.

You could smooth over this with an inspection unit test, which checks the strings against their types to see if the property exists, but that smells, it’s not a very good library if you have to verify it even works. I could’ve also created a static class to represent the Customer instance properties, but that’s more noise (you’d need 3 classes, instead of just 2); a pre-build step (ala SubSonic) came to mind, but that’s entering into the realm of diminished returns.

Conclusion?

Sometimes the obvious way is the best way. Old fashioned may be old, but that doesn’t make it wrong. Sometimes a cigar is just a cigar.

Introducing the filterable DeleGrid

The DeleGrid is a paged GridView control that handles data-binding through the use of events and delegates rather than with a traditional collection.

What this means is that you have full control over the data that is shown in the currently displayed page. Traditionally you’d retrieve the whole recordset then page it locally, but with the DeleGrid you can utilise your database/ORMs paging features.

To quote myself from when I first introduced the DeleGrid:

[The DeleGrid] came about because I wanted a nice way of implementing paging using NHibernate without having the grid know about it. I really didn’t want NHibernate to leave my data layer, so I needed a nice way of the grid calling my DAL with the paging parameters.

What’s new?

The biggest change in version 1.1 is the introduction of filtering. The filter isn’t generated in some black-box fashion, instead it’s defined by the programmer. It’s built up from the columns in the grid, which define their own filtering behavior.

The filter acts upon any columns in the grid that implement the IFilterableField interface. Implementing this interface in your own fields is easy, so you’re quickly able to create custom filtering behavior for your grid. An example would be a date column, that has a date-picker as a filter control.

Filter Screenshot

I’ve chosen not to implement the wealth of appearance customisations that are available in the normal templated controls. This is down to two reasons, firstly I don’t agree with it, appearance should be controlled soley through CSS. Secondly, there are so many, I couldn’t be bothered. So you’re only able to attach CSS classes to the buttons and cells, and specify the image urls for the buttons.

An example implementation

The grid now has a companion project, it’s own data library. This separation is to keep you from having to reference System.Web in your data-layer. To use the DeleGrid in your project you’ll need to reference JAGregory.Controls.DeleGrid.dll and the JAGregory.Controls.Data.dll in your web project, then reference JAGregory.Controls.Data.dll in your data layer, if they’re separate projects.

So to begin with, add the reference to JAGregory.Controls.DeleGrid.dll and JAGregory.Controls.Data.dll into your web project. This will allow you to use the DeleGrid in your page. Once you’ve done that, you’ll need to reference the control in your page, you can either do this using a Register tag in your page, or in the web.config as so:

<pages>
  <controls>
    <add tagPrefix="jag" namespace="JAGregory.Controls"
      assembly="JAGregory.Controls.DeleGrid" />
  </controls>
</pages>

With that in place, you can now put the DeleGrid into your page:

<jag:DeleGrid ID="grid" Runat="server" AllowFiltering="true"
  AutoGenerateColumns="false">
    <FilterStyle ToggleOnImageUrl="img/find.png" ToggleOffImageUrl="img/find.png"
      ExecuteImageUrl="img/go.png" />
    <Columns>
        <jag:FilterableTextField HeaderText="Name" DataField="Name" />
        <jag:FilterableBooleanField HeaderText="Active" DataField="Active" />
    </Columns>
</jag:DeleGrid>

n.b. In this example I’m using a Customer object to bind against it, which simply has the Name and Active properties.

For this grid we’ve set AllowFiltering to true, which enables the filter, then we’ve set AutoGenerateColumns to false so we can add our own custom columns. The two columns both implement the aforementioned IFilterableField interface, which allows them to define their own filtering behavior.

I’ve also set the image urls so the buttons will be visible.

Now that the page is set up, we need to get down to the binding. In your code-behind:

protected override void OnInit(EventArgs e)
{
    base.OnInit(e);

    // attach the events for requesting the data and totals
    grid.TotalRecordCountRequest += grid_TotalRecordCountRequest;
    grid.PageDataRequest += grid_PageDataRequest;
}

protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);

    if (!IsPostBack)
        grid.DataBind();
}

What’ve just done is attach the TotalRecordCountRequest and PageDataRequest handlers to the grid, which respectively fetch the total record count for the full grid, and fetch the current page of data from the database; the implementations are below.

private IEnumerable grid_PageDataRequest(object sender, PageDataRequestEventArgs e)
{
    CustomerRepository repos = new CustomerRepository();

    // get the requested page of data from the database
    return repos.FindAllPaged(e.Range, e.Sort, e.Filters);
}

private int grid_TotalRecordCountRequest(object sender, DataRequestEventArgs e)
{
    CustomerRepository repos = new CustomerRepository();

    // get the total records
    return repos.GetAllCount(e.Filters);
}

I’m using a repository pattern to handle data-access. In the PageDataRequest handler we’re taking the range, sort, and filter info that the grid passed us and sending it off to the repository to get the data. Similarily the TotalRecordCountRequest handler does a similar thing but without the range or sort info.

That’s it really for using the DeleGrid, you just need to take the filter info and handle it using your specific ORM.

Repository implementation

Ok I’ll throw you a bone, here’s the repository implementation to show how easy it is using NHibernate:

public class CustomerRepository
{
    /// <summary>
    /// Creates a NHibernate ICriteria based on the filters.
    /// </summary>
    /// <param name="filters">Filters to apply.</param>
    /// <returns>ICriteria</returns>
    private ICriteria CreateFilteredCriteria(FilterCriterionCollection filters)
    {
        ICriteria criteria = SessionManager.CurrentSession
            .CreateCriteria(typeof(Customer));

        // criterion handling - write this yourself depending on how your
        // db filters (and what filter types you're supporting)
        foreach (FilterCriterion filter in filters)
        {
            if (filter.Type == typeof(string))
                criteria.Add(Expression.Like(filter.FieldName, "%" + filter.Value + "%"));
            else if (filter.Type == typeof(bool))
                criteria.Add(Expression.Eq(filter.FieldName, filter.Value));
        }

        return criteria;
    }

    /// <summary>
    /// Gets the total record count from the database using the filters.
    /// </summary>
    /// <param name="filters">Filters to apply before getting the count.</param>
    /// <returns>Total number of records in the filtered list</returns>
    public int GetAllCount(FilterCriterionCollection filters)
    {
        return CreateFilteredCriteria(filters)
            .SetProjection(Projections.Count("ID"))
            .UniqueResult<int>();
    }

    /// <summary>
    /// Gets one page of data from the database.
    /// </summary>
    /// <param name="range">Select range (start ID and number of records).</param>
    /// <param name="sort">Sorting to apply.</param>
    /// <param name="filters">Filters to apply.</param>
    /// <returns>List for one page of data.</returns>
    public IList<Customer> FindAllPaged(SelectRange range, SortInfo sort, FilterCriterionCollection filters)
    {
        // create the criteria using the filters, then set the range
        ICriteria criteria = CreateFilteredCriteria(filters)
            .SetFirstResult(range.Start)
            .SetMaxResults(range.Size);

        // only add the sort if one is specified
        if (!string.IsNullOrEmpty(sort.Field))
        {
            if (sort.Direction == Direction.Asc)
                criteria.AddOrder(Order.Asc(sort.Field));
            else
                criteria.AddOrder(Order.Desc(sort.Field));
        }

        return criteria.List<Customer>();
    }
}

The CreateFilteredCriteria method is doing most of the leg work. It takes creates an NHibernate criteria, then adds any filter criterions to it. It iterates the filters collection, checking their type and adding the appropriate NHibernate criterion. Simple!

The example project

I’ve attached a sample project that uses the grid to display a collection of customers that are paged and filtered. The example uses a SQLite database with NHibernate for data-access, I’ve done this to keep the extraneous code to a minimum.

Downloads

The DeleGrid is open-source under the new BSD License; read the license for what you’re allowed to do.

You can download the source here: Download Source.
You can download the latest binary here: Download Binary.
You can download the example project here: Download Example.

The source is also accessible from Subversion at: http://jagregory.googlecode.com/svn/trunk/DeleGrid/ (using user jagregory-read-only)

ObjectField 1.1

I’ve updated the ObjectField to be considerably simpler than it was before. While writing my Data-binding hierarchical objects post I wrote this about the BoundField implementation:

Using a TypeDescriptor to get the property… This strikes me as a bit odd to be honest, because the DataBinder has the ability to evaluate a hierarchical path.

Which is interesting, because I was using a TypeDescriptor in my ObjectField implementation!

Originally, the ObjectField was using the method below to evaluate the hierarchical paths, which to be honest is a bit verbose.

private object GetNestedValue(object component, string field)
{
	string[] properties = field.Split('.');

	foreach (string property in properties)
	{
		PropertyDescriptor descriptor =
			TypeDescriptor.GetProperties(component).Find(property, true);

		if (descriptor == null && !AllowNulls)
		{
			// no descriptor, and we're not allowing nulls so complain that
			// we can't find the object
			throw new HttpException(string.Format(MissingFieldErrorMessage,
				property));
		}
		else if (descriptor == null)
		{
			// silently return, with the NullValue if present
			component = NullValue;
			break;
		}

		component = descriptor.GetValue(component);
	}

	return component;
}

The GetNestedValue method was splitting the DataField value and then recursively evaluating each property.

Here’s the same implementation using the DataBinder:

// looking to bind against child-objects
object component = DataBinder.GetDataItem(controlContainer);

return DataBinder.Eval(component, DataField);

Magic!

As a side effect of this change, the ObjectField can now support everything regular data-binding does. So you can use indexers and such in your DataField now.

A couple of other things you should know: the AllowNulls property has been removed because it’s no longer supported, and the NullValue field has also been removed because the BoundField already supported it in the form of NullDisplayText.

Downloads

The ObjectField is open-source under the new BSD License; read the license for what you’re allowed to do.

You can download the source here: Download Source.
You can download the latest binary here: Download Binary.

The source is also accessible from Subversion at: http://jagregory.googlecode.com/svn/trunk/ObjectField/ (using user jagregory-read-only)