Tuesday, July 31, 2012

Game of Life Exercise and Extension Methods

A quick attempt in writing the Game of Life simulator using WPF. As a side goal, I wanted to better understand the extension methods in C# so I tried to move as much code as possible into the Helper class without sacrificing readability.

PopulateGrid adds 50 rows and columns to a WPF Grid, creating a 50x50 matrix of cell. It then adds a rectangle to each cell so coloring could be applied. RePaintCell changes the background color of the cell at position i,j. InitializeArray just fills a 50x50 array of booleans, each value representing either a live or dead cell. CheckCell checks a single cell to find out if it will be live or dead in the next iteration. FillArray uses CheckCell to analyse the current array and construct the array of the next iteration. DrawArray compares the current and next iterations. If there is difference in the color of the cell at i,j, this cell is painted appropriately, otherwise it is skipped. Finally, AddGlider adds a glider element to the empty array so it was easy to test that the game runs correctly. The full listing is below.

MainWindow.xaml

<Window x:Class="GameOfLife.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="386" Width="525">
    <Grid Name="MainGrid">
        <Grid Name="DynamicGrid" ShowGridLines="True">
        </Grid>
        <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="25,316,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
    </Grid>
</Window>

MainWindow.xaml.cs

using System.Windows;
using System.Windows.Media;
using System.Windows.Threading;
using System;

namespace GameOfLife
{
    public partial class MainWindow : Window
    {
        private bool[,] arrOne = new bool[Helper.x, Helper.y];
        private bool[,] arrTwo = new bool[Helper.x, Helper.y];
        private DispatcherTimer dt = new DispatcherTimer();
        private int count;

        public MainWindow()
        {
            InitializeComponent();
            dt.Interval = TimeSpan.FromMilliseconds(100);
            dt.Tick += dt_Tick;
            dt.Start();
            Loaded += MainWindow_Loaded;
        }

        void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            DynamicGrid.PopulateGrid(new SolidColorBrush(Colors.Blue));
            InitializeGame();
        }

        void InitializeGame()
        {
            arrOne.InitializeArray(false);
            arrTwo.InitializeArray(false);
            arrOne.AddGlider(20, 30);
            arrOne.DrawArray(arrTwo, DynamicGrid);
        }

        void dt_Tick(object sender, EventArgs e)
        {
            if(true)
            {
                bool[,] arrCurrent = count%2 == 0 ? arrOne : arrTwo;
                bool[,] arrNext = count%2 == 0 ? arrTwo : arrOne;

                arrNext.FillArray(arrCurrent);
                arrNext.DrawArray(arrCurrent, DynamicGrid);
                count++;
            }
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            if(dt.IsEnabled)
                dt.Stop();
            else
                dt.Start();
        }
    }
}

Helper.cs

using System.Linq;
using System.Windows.Controls;
using System.Windows.Shapes;
using System.Windows.Media;

namespace GameOfLife
{
    public static class Helper
    {
        public const int x = 50;
        public const int y = 50;

        public static void PopulateGrid(this Grid grid, SolidColorBrush brush)
        {
            for (int i = 0; i < y; i++)
            {
                grid.RowDefinitions.Add(new RowDefinition());
            }

            for (int j = 0; j < x; j++)
            {
                grid.ColumnDefinitions.Add(new ColumnDefinition());
            }

            for (int i = 0; i < y; i++)
            {
                for (int j = 0; j < x; j++)
                {
                    Rectangle rect = new Rectangle();
                    rect.SetValue(Grid.RowProperty, i);
                    rect.SetValue(Grid.ColumnProperty, j);
                    rect.Fill = brush;
                    grid.Children.Add(rect);
                }
            }
        }

        public static void RePaintCell(this Grid grid, int i, int j, SolidColorBrush brush)
        {
            Rectangle cell = grid.Children.Cast<Rectangle>().First(r => Grid.GetRow(r) == j && Grid.GetColumn(r) == i);
            cell.Fill = brush;
        }

        public static void InitializeArray<T>(this T[,] arr, T value)
        {
            int iDim = arr.GetLength(0);
            int jDim = arr.GetLength(1);
            for (int i = 0; i < iDim; i++)
            {
                for (int j = 0; j < jDim; j++)
                {
                    arr[i, j] = value;
                }
            }
        }

        public static void AddGlider(this bool[,] arr, int x, int y)
        {
            arr[x - 1, y] = false;
            arr[x - 1, y + 1] = false;
            arr[x - 1, y + 2] = true;

            arr[x, y] = true;
            arr[x, y + 1] = false;
            arr[x, y + 2] = true;

            arr[x + 1, y] = false;
            arr[x + 1, y + 1] = true;
            arr[x + 1, y + 2] = true;
        }

        public static void FillArray(this bool[,] arr, bool[,]arrCurrent)
        {
            for (int i = 0; i < y; i++)
            {
                for (int j = 0; j < x; j++)
                {
                    arr[i, j] = arrCurrent.CheckCell(i, j);
                }
            }
        }

        public static void DrawArray(this bool[,] arr, bool[,] arrCurrent, Grid grid)
        {
            SolidColorBrush redBrush = new SolidColorBrush(Colors.Red);
            SolidColorBrush blueBrush = new SolidColorBrush(Colors.Blue);

            for (int i = 0; i < y; i++)
            {
                for (int j = 0; j < x; j++)
                {
                    if (arr[i, j] != arrCurrent[i, j])
                    {
                        SolidColorBrush brush = arr[i, j] ? redBrush : blueBrush;
                        grid.RePaintCell(i, j, brush);
                    }
                }
            }
        }

        public static bool CheckCell(this bool[,] arr, int i, int j)
        {
            int nextI = i == (x - 1) ? 0 : i + 1;
            int prevI = i == 0 ? x - 1 : i - 1;
            int nextJ = j == (y - 1) ? 0 : j + 1;
            int prevJ = j == 0 ? y - 1 : j - 1;

            bool[] neighbours = new[]{
                                        arr[prevI, prevJ],   arr[i, prevJ],   arr[nextI, prevJ],
                                        arr[prevI, j],       arr[nextI, j],   arr[prevI, nextJ],
                                        arr[i, nextJ],       arr[nextI, nextJ]
                                    };

            int val = neighbours.Count(c => c);

            if (arr[i, j])
                return (val >= 2 && val <= 3) ? true : false;
            else
                return (val == 3) ? true : false;
        }
    }
}

Reference

Conway's Game of Life

The results are impressive

by . Also posted on my website

Tuesday, July 17, 2012

Learning MVC: Vertical Pop-Out Menu

Adding a pop-out menu to the application turned out to be two major steps. The second step can be broken down into obvious sub-steps too:

  • Create HTML structure for the menu and apply the CSS
  • Create a ViewModel for the menu partial view and fill it with data
    • Create a ViewModel
    • Create a controller to fill it with data
    • Modify the view to render the ViewModel properly

The first step I'm not describing here because I used a well-written tutorial[1]. I will only record here the styles I added to Site.css:

#menu {
    width: 12em;
    background: #eee;
}

#menu ul {
    list-style: none;
    margin: 0;
    padding: 0;
}

#menu a, #menu h2 {
    font: bold 11px/16px arial, helvetica, sans-serif;
    display: block;
    border-width: 1px;
    border-style: solid;
    border-color: #ccc #888 #555 #bbb;
    margin: 0;
    padding: 2px 3px;
}

#menu h2 {
    color: #fff;
    background: #000;
    text-transform: uppercase;
}

#menu a {
    color: #000;
    background: #efefef;
    text-decoration: none;
}

#menu a:hover {
    color: #a00;
    background: #fff;
}

#menu li {position: relative;}

#menu ul ul ul {
    position: absolute;
    top: 0;
    left: 100%;
    width: 100%;
}

div#menu ul ul ul,
div#menu ul ul li:hover ul ul
{display: none;}

div#menu ul ul li:hover ul,
div#menu ul ul ul li:hover ul
{display: block;}

The second step I'll write down in more detail.

1. Create a partial view for the left sidebar. I decided to render the partial view by calling Html.Action, so I modified the div that holds the left sidebar in _Layout.shtml to look like this:

<div id="left-sidebar">
 @Html.Action("MenuResult", "LeftMenu")
</div>

Then I created a partial view called MenuResult.shtml and placed it in the Shared folder. This is how the HTML structure looks like:

@model Recipes.Models.LeftMenuViewModel

@{ Layout = null; }

<div id="menu">
    <ul>
        <li><h2>Recipes Menu</h2>
            <ul>
                <li>@Html.ActionLink("Recipes", "../Recipe/Index")
                    <ul>
                         <li>Test menu item
                            <ul>
                                    <li>Test child menu item</li>
                            </ul>
                        </li>                           
                    </ul>
                </li>
            </ul>
        </li>
    </ul>
</div>

2. ViewModel. After I was satisfied with the way the "stub" menu works, I started working on the model for the partial view. My first attempt looked something like this, a pretty simple model:

public class LeftMenuViewModel
{
 public List<Category> Categories { get; set; }
}

And a pretty simple nested foreach iterator that attempts to render the view:

<ul>
 <li>@Html.ActionLink("Recipes", "../Recipe/Index")
  <ul>
   @foreach(var cat in Model.Categories)
   {
    <li>@Html.ActionLink(cat.CategoryName, @Html.CategoryAction(cat.CategoryID).ToString())
    <ul>
     @foreach(var subcat in cat.SubCategories)
     {
      <li>@Html.ActionLink(subcat.SubCategoryName, @Html.SubCategoryAction(subcat.SubCategoryID).ToString())</li>
     }
    </ul>
   </li>                           
   }
  </ul>
 </li>
</ul>

3. Controller. The initial version of the controller looked something like this:

public class LeftMenuController : Controller
{
 public PartialViewResult MenuResult()
 {
  LeftMenuViewModel viewModel = new LeftMenuViewModel();

  using (RecipesEntities db = new RecipesEntities())
  {
   viewModel.Categories = db.Categories.ToList();
   foreach (var cat in viewModel.Categories)
   {
    cat.SubCategories = db.SubCategories.Where(s => s.CategoryID == cat.CategoryID).ToList();
   }
  }
  return PartialView(viewModel);
 }
}

That was the initial attempt, but when I ran this, I was presented with the following exception: The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.

The ObjectContext instance has been disposed

That looked a bit weird to me - I can see the elements of the collection, but the application refuses to iterate through them, complaining about the context. I found a couple of thoughtful posts on the reason for such a behaviour. First post [2] suggested that most likely, the execution of the query was deferred and now, in the view, when it actually tries to execute the query, I have disposed of the DbContext already and it fails. The suggestion was to convert the query results to list using .ToList() so the query gets executed before disposing. That did not work. Another post [3] suggested replacing the foreach iterator with a for one for a number of reasons, but that did not help either.

I gave it some thought and chose an easy way out - remove the dependency on the LINQ and complex entity objects and create my own very simple class to use in the view model. Here is the final code, which worked for me:

View Model

public class LeftMenuViewModel
{
 public List<MenuElement> elements { get; set; }
}

public class MenuElement
{
 public int id { get; set; }
 public string name { get; set; }
 public List<MenuElement> children { get; set; }

}

Controller

public class LeftMenuController : Controller
{
 public PartialViewResult MenuResult()
 {
  LeftMenuViewModel viewModel = new LeftMenuViewModel();
  viewModel.elements = new List<MenuElement>();

  using (RecipesEntities db = new RecipesEntities())
  {
   List<Category> cats = db.Categories.ToList();
   foreach (var category in cats)
   {
                MenuElement element = new MenuElement() {id = category.CategoryID, name = category.CategoryName, children = new List<MenuElement>()};

    List<SubCategory> subcats =
     db.SubCategories.Where(s => s.CategoryID == category.CategoryID).ToList();

    foreach (var subcat in subcats)
    {
     element.children.Add(new MenuElement(){id = subcat.SubCategoryID, name = subcat.SubCategoryName} );
    }
    viewModel.elements.Add(element);
   }
  }
  return PartialView(viewModel);
 }
}

View

@model Recipes.Models.LeftMenuViewModel

@{ Layout = null; }

<div id="menu">
    <ul>
        <li><h2>Recipes Menu</h2>
            <ul>
                <li>@Html.ActionLink("Recipes", "../Recipe/Index")
                    <ul>

                        @for(int i=0; i<Model.elements.Count(); i++)
                        {
                         <li>@Html.ActionLink(Model.elements[i].name, @Html.CategoryAction(Model.elements[i].id).ToString())
                            <ul>
                                @for(int j=0; j<Model.elements[i].children.Count(); j++)
                                {
                                    <li>@Html.ActionLink(Model.elements[i].children[j].name, @Html.SubCategoryAction(Model.elements[i].children[j].id).ToString())</li>
                                }
                            </ul>
                        </li>                           
                        }
                    </ul>
                </li>
            </ul>
        </li>
    </ul>
</div>

While this looks a bit more complex compared to the initial attempt, I think there is really much less space for error. Here is how the menu looks like:

Left side pop-out menu

References:

CSS Pop-Out Menu Tutorial
The ObjectContext instance has been disposed and can no longer be used for operations that require a connection
MVC Razor view nested foreach's model by . Also posted on my website

Thursday, July 5, 2012

Learning MVC: Editing the Variable Length List

Continuing the recipe database example, the next step is to not just keep a list of ingredients that are required for a recipe, but also to allow specifying the quantity of each ingredient. Up to this point, I did not need any "mapping table" due to the MVC magic - the Recipe object kept a list of ingredients, and the Ingredient object kept a list of recipes. That was all that MVC needed to resolve the many-to-many relationship between recipes and ingredients and I could get away with just two models.

Now that I want to know how much of the ingredient is required, I don't have a place to save this information. I don't think I can get away without the RecipeIngredient model any longer. I'm adding that and also giving the user the ability to add and remove ingredients. This requires a technique to edit and save a list of variable length, which is referenced at the end of this post and which I applied, with small modifications.

To display the list, the following technique is used: a div element which contains one entry from the list is placed in a partial view. Each time the user adds an entry to the list, another such div is appended to the list using an Ajax call to a jQuery append() function. Each time the user removes an entry, a div is removed, which is even easier. To begin with, I added the following to the recipe's Edit view

<fieldset>
 <div id="editorRows">
 <ol>
  @foreach (var item in Model.RecipeIngredients)
  {
   @Html.Partial("_RIEditor", item)
  }
 </ol>
 </div>
 @Html.ActionLink("Add another ...", "Add", null, new {id = "addItem"})
</fieldset>

The same partial view _RIEditor is repeated once per each ingredient. The "Add another ..." link will later add an ingredient when the user clicks it. And here's a sample _RIEditor partial view ( the Layout=null part was added because otherwise my partial view was rendered with the header and the footer).

@using Recipes.HtmlHelpers
@model Recipes.Models.RecipeIngredient
           
@{ Layout = null; }

<div class="editorRow">
    @using (Html.BeginCollectionItem("RecipeIngredients"))
    {
        <li class="styled">
        <div class="display-label">Ingredient:</div>@Html.TextBoxFor(model => model.Ingredient.IngredientName)
        <div class="display-label-nofloat">Amount:</div>@Html.TextBoxFor(model => model.Quantity, new { size = 4 })
        <a href="#" class="deleteRow">delete</a>
        </li>
    }
</div>

The key part here is the Html.BeginCollectionItem, which renders a sequence of items that will later be bound to a single collection. In short, it keeps track of the items as they are added or deleted, and when the form is finally submitted, the neat collection of items is returned, ready to be saved to database.

Now to allow for adding or deleting elements, I need to add two functions. Here's the example:

<script type="text/javascript">
<!--
    $("#addItem").click(function () {
        $.ajax({
            url: this.href,
            cache: false,
            success: function (html) { $("#editorRows").append(html); }
        });
        return false;
    });

    $("a.deleteRow").live("click", function () {
        $(this).parents("div.editorRow:first").remove();
        return false;
    });
-->
</script>

I also need to reference a couple of JavaScript files to make it work

<script src="@Url.Content("~/Scripts/MicrosoftAjax.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/MicrosoftMvcValidation.debug.js")" type="text/javascript"></script>

Almost done, now I only need to take care of that "Add another ..." link that I added to the Edit view. To make it work, I only need a simple action added to the controller. which will return the partial view.

public ViewResult Add()
{
 return View("_RIEditor", new RecipeIngredient());
}

So, what have I achieved? Here's the first approximation of how my ingredient list may look like when I load the recipe from the database

Original List of Ingredients

And how it looks when I click "Add another ...": a line for a new ingredient is added, looking the same as other lines and I can enter some data

Modified List of Ingredients

And then I can verify that some data is returned back on Submit, so my changes are not being lost

Data Posted by the View

The concept is working at this point - I get back my three "RecipeIngredients" and the data I entered. It's only the proof of concept at this point, I need to make a number of modifications to make it functional.

References:

BeginCollectionItem source code
Editing a variable length list, ASP.NET MVC 2-styleby . Also posted on my website