Current Work

Quote of the day #1

“There has been much tragedy in my life; at least half of it actually happened”

Advertisements
ASP MVC, C#, CodeProject, Current Work

Better ASP MVC Select HtmlHelper

As a lot of you who have read stuff I have written about before will know that I am mainly interested in desktop development, WPF in fact. You may have also noticed that my blog has been a bit quite lately, which is due to the fact I am working on a pretty large open source project using ASP MVC 3, which is eating all my spare time, as such I have not been writing as many articles as I had been. The open source project is coming along nicely, and I am getting closer to completing it.

During the course of working on this open source project I have been trying to write ASP MVC 3 code using best practices and have an excellent ASP MVC clued up colleague who answers my dumb questions.

Now the other day I asked him why the standard HtmlHelper.DropDown and HtmlHelper.DropDownFor extension methods require you to use some really filthy objects such as SelectListItem.

Now I don’t know who will be reading this post, but I come from WPF land which kind of paved the way for the ModelViewViewModel  pattern, which ASP MVC seems to borrow for its Model approach these days. I think it is fair to say that most ASP MVC devs will be treating their Models and View specific Models AKA ViewModels.

So we have this Model for the View (AKA ViewModel), which gets bound to a Razor view using ASP MVCs Model Binding (assuming you are using Razor view engine and not just some REST/JSON/JQuery Ajax approach where you miss the view engine out altogether, that’s cool stuff too, but not the subject of this post). Ok so far, but now I want to create a DropDownList (HTML Select tag) using one of the existing HtmlHelper.DropDownList and HtmlHelper.DropDownListFor extension methods. This is where the fun starts, I now have to pollute my nice clean view specific model (ViewModel) with crap which in my opinion, is a view concern.

Ok you could argue that the Model is view specific so what is the harm in having a IEnumerable<SelectList> property in there. Well it just doesn’t sound right to me, and lets push the boat out a bit more, and imagine I want to test my Models. They now have UI Specific stuff in them, so my tests now have to know about UI specific stuff. Which again sounds wrong to me.

Ok I don’t know what your tests look like, but mine have separate test suites for models, than I do for my controller tests. In my test suite where I am testing my controllers I half expect a bit of stuff to do with view specifics such as ViewData, Session, ActionResults etc etc, but in my models I just don’t want any UI stuff in there.

So what can we do about it.

Well the answer is surprisingly simple, we just create our own HtmlHelper which does a better job and allows us to maintain a nice clean model and allows better separation of concerns.

Ok lets have a look at the finished code then shall we. Oh one thing before we start, I am using a standard ASP MVC 3 project that you get when you start a new ASP MVC Razor based project from within Visual Studio 2010, so I hope you are familiar with that and the objects it creates.

The Model

This is dead easy, and just exposes the model data. Notice how I do not have an UI stuff like SelectList in here. Its just standard data. Obviously this will vary for your specific requirements

This is a demo model

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace MvcApplication1.Models
{
    public class Person
    {
        public int Id { get; private set; }
        public string Name { get; private set; }
        public Person(int id, string name)
        {
            this.Id = id;
            this.Name = name;

        }

        public override string ToString()
        {
            return String.Format("Id : {0}, Name : {1}", Id, Name);
        }
    }


    public class PeopleViewModel
    {
        public int SelectedPersonId { get; set; }
        public List<Person> Staff { get; set; }

        public PeopleViewModel()
        {

        }
        
        public PeopleViewModel(int selectedPersonId, List<Person> staff)
        {
            this.SelectedPersonId = selectedPersonId;
            this.Staff = staff;
        }
    }


}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

 

The HtmlHelper

This is where the real work is done, and I came up with 2 approaches which are both shown below. The attached source code has them both in but only one is active, the other is commented out. I will leave it to the user to decide which they prefer.

However one thing both approaches have in common is that they use Expression<Func<T,Object>> to obtain all the information required to create the html select using the models properties. This can be seen below where I show a demo of it within the demo view.

Option 1 : Defer to the standard HtmlHelper

This option defers to the standard HtmlHelper.DropDownList but this new HtmlHelper creates the SelectList(s) for the standard HtmlHelper.DropDownList

 

using System;
using System.Text; 
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using MvcApplication1.Helpers;

namespace MvcApplication1.MyHelpers
{
    public static class HtmlHelperExtensions
    {
        /// <summary>
        /// Provides a better HtmlHelper dropdown list function
        /// that is type safe and does not fill your model with View specific gunk
        /// </summary>
        /// <typeparam name="TModel">The Model type</typeparam>
        /// <typeparam name="TItem">An item type from the source list</typeparam>
        /// <typeparam name="TValue">A value type for one of the items 
        /// in the source list</typeparam>
        /// <typeparam name="TKey">A text type for one of the items 
        /// in the source list</typeparam>
        /// <param name="htmlHelper">The actual HtmlHelper</param>
        /// <param name="selectedItemExpr">An expression which selects 
        /// the selected item from the model</param>
        /// <param name="enumerableExpr">An expression which selects 
        /// the source list from the model</param>
        /// <param name="valueExpr">An expression that selects a 
        /// value from an item</param>
        /// <param name="keyExpr">An expression that selects text 
        /// value from an item</param>
        /// <param name="htmlAttributes">The Html Attributes to apply 
        /// to the overall select string which gets rendered</param>
        /// <returns>A HTML encoded string, which represents a HTML 
        /// select tag with the attributes provided</returns>
        public static MvcHtmlString ComboFor<TModel, TItem, TValue, TKey>(
            this HtmlHelper<TModel> htmlHelper,
            Expression<Func<TModel, TValue>> selectedItemExpr,
            Expression<Func<TModel, IEnumerable<TItem>>> enumerableExpr,
            Expression<Func<TItem, TValue>> valueExpr,
            Expression<Func<TItem, TKey>> keyExpr,
            IDictionary<string, object> htmlAttributes) where TValue : IComparable
        {
            TModel model = (TModel)htmlHelper.ViewData.Model;

            string id = ExpressionUtils.GetPropertyName(selectedItemExpr);

            TValue selectedItem = selectedItemExpr.Compile()(model);
            IEnumerable<TItem> sourceItems = enumerableExpr.Compile()(model);

            Func<TItem, TKey> keyFunc = keyExpr.Compile();
            Func<TItem, TValue> valueFunc = valueExpr.Compile();

            List<SelectListItem> selectList =
                (from item in sourceItems
                 let itemValue = valueFunc(item)
                 let itemKey = keyFunc(item)
                 select new SelectListItem()
                     {
                         Selected = selectedItem.CompareTo(itemValue) == 0,
                         Text = itemKey.ToString(),
                         Value = itemValue.ToString()
                     }).ToList();

            return htmlHelper.DropDownList(
                   id.ToString(), selectList, htmlAttributes);
        }
    }
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

 

Option 2 : Do all the work ourselves

This option means we MUST do everything that a standard HtmlHelper extension method would do, which means taking care of things like “Name” and “Id” for the generated html, and also ensuring its rendering correctly using a html encoded string

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using MvcApplication1.Helpers;
using System.Text;

namespace MvcApplication1.MyHelpers
{
    public static class HtmlHelperExtensions
    {
        /// <summary>
        /// Provides a better HtmlHelper dropdown list function
        /// that is type safe and does not fill your model with View specific gunk
        /// </summary>
        /// <typeparam name="TModel">The Model type</typeparam>
        /// <typeparam name="TItem">An item type from the source list</typeparam>
        /// <typeparam name="TValue">A value type for one of the items 
        /// in the source list</typeparam>
        /// <typeparam name="TKey">A text type for one of the items 
        /// in the source list</typeparam>
        /// <param name="htmlHelper">The actual HtmlHelper</param>
        /// <param name="selectedItemExpr">An expression which selects 
        /// the selected item from the model</param>
        /// <param name="enumerableExpr">An expression which selects 
        /// the source list from the model</param>
        /// <param name="valueExpr">An expression that selects a 
        /// value from an item</param>
        /// <param name="keyExpr">An expression that selects text 
        /// value from an item</param>
        /// <param name="htmlAttributes">The Html Attributes to apply 
        /// to the overall select string which gets rendered</param>
        /// <returns>A HTML encoded string, which represents a HTML 
        /// select tag with the attributes provided</returns>
        public static MvcHtmlString ComboFor<TModel, TItem, TValue, TKey>(
            this HtmlHelper<TModel> htmlHelper,
            Expression<Func<TModel, TValue>> selectedItemExpr,
            Expression<Func<TModel, IEnumerable<TItem>>> enumerableExpr,
            Expression<Func<TItem, TValue>> valueExpr,
            Expression<Func<TItem, TKey>> keyExpr,
            IDictionary<string, object> htmlAttributes) where TValue : IComparable
        {
            TModel model = (TModel)htmlHelper.ViewData.Model;

            string id = ExpressionUtils.GetPropertyName(selectedItemExpr);

            TValue selectedItem = selectedItemExpr.Compile()(model);
            IEnumerable<TItem> sourceItems = enumerableExpr.Compile()(model);

            Func<TItem, TKey> keyFunc = keyExpr.Compile();
            Func<TItem, TValue> valueFunc = valueExpr.Compile();

 

            TagBuilder selectBuilder = new TagBuilder("select");
            selectBuilder.GenerateId(id.ToString());
            selectBuilder.MergeAttribute("name", id, true);
            selectBuilder.MergeAttributes(htmlAttributes, true);

            StringBuilder optionsBuilder = new StringBuilder();

            foreach (TItem item in sourceItems)
            {
                TagBuilder optionBuilder = new TagBuilder("option");
                object itemValue = valueFunc(item);
                object itemKey = keyFunc(item);

                optionBuilder.MergeAttribute("value", itemValue.ToString());
                optionBuilder.SetInnerText(itemKey.ToString());

                if (selectedItem.CompareTo(itemValue) == 0)
                {
                    optionBuilder.MergeAttribute("selected", "selected");
                }
                optionsBuilder.AppendLine(MvcHtmlString.Create(
                    optionBuilder.ToString(TagRenderMode.Normal)).ToString());
            }

            selectBuilder.InnerHtml = optionsBuilder.ToString();

            MvcHtmlString x = MvcHtmlString.Create(
                selectBuilder.ToString(TagRenderMode.Normal).ToString());

            return x;
        }

    }
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

This code also makes use of this utility class to grab the name of a property from an Expression
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Linq.Expressions;
using System.Reflection;

namespace MvcApplication1.Helpers
{
    public static class ExpressionUtils
    {

        public static string GetPropertyName<TModel, TItem>(
           Expression<Func<TModel, TItem>> propertyExpression)
        {
            var lambda = propertyExpression as LambdaExpression;
            MemberExpression memberExpression;
            if (lambda.Body is UnaryExpression)
            {
                var unaryExpression = lambda.Body as UnaryExpression;
                memberExpression = unaryExpression.Operand as MemberExpression;
            }
            else
            {
                memberExpression = lambda.Body as MemberExpression;
            }

            var propertyInfo = memberExpression.Member as PropertyInfo;

            return propertyInfo.Name;
        }

    }
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

 

A Demo View

This is a small demo view that goes with the model/controller supplied at the bottom of this post. Again you will need to change this depending on your own requirements

Note the “using” at the top of the view which lets us include our new HtmlHelper extension method

Also note how we use the new HtmlHelper extension method, the selection of the

  • Source list (The IEnumerable<T>)
  • Option key value
  • Option text value

Is all done using Expression<Func<T,Object>> which is nice a type safe.

@model MvcApplication1.Models.PeopleViewModel
@using MvcApplication1.MyHelpers
@{
    ViewBag.Title = "PeopleView";
}


@using (Html.BeginForm("Create", "Home", FormMethod.Post))
{
    <h2>PeopleView</h2>

    <p>Select an item and click "Submit" button</p>
    
    @Html.ComboFor(
        x => x.SelectedPersonId, 
        x => x.Staff, 
        x => x.Id, 
        x => x.Name,
        new Dictionary<string, object> { { "class", "SomeSelectorClass" } })

    <br />
    <br />
    <br />
 
    if (ViewData["result"] != null)
    {
        <p>@ViewData["result"].ToString()</p>
    }
    
    
    <input id="peopleSubmit" type="submit" value="submit" />    
    
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

 

So when the HtmlHelper presented with this post does its job this is what the Razor view engine outputs

<select class="SomeSelectorClass" id="SelectedPersonId" name="SelectedPersonId">
<option value="1">Sam Brown</option>
<option selected="selected" value="2">Bob Right</option>
<option value="3">Henry Dune</option>
</select>

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

 

A Demo Controller

This is a small demo controller that goes with the model/controller supplied at the bottom of this post. Again you will need to change this depending on your own requirements

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MvcApplication1.Models;

namespace MvcApplication1.Controllers
{
    public class HomeController : Controller
    {
      
        public ActionResult Create(PeopleViewModel vm)
        {
            List<Person> staff = new List<Person>();
            staff.Add(new Person(1, "Sam Brown"));
            staff.Add(new Person(2, "Bob Right"));
            staff.Add(new Person(3, "Henry Dune"));

            PeopleViewModel vmnew = 
                new PeopleViewModel(
                    vm.SelectedPersonId, staff);

            ViewData["result"] = 
                string.Format("The selected item was {0}",
                (from x in staff 
                 where x.Id == vm.SelectedPersonId 
                 select x).Single().ToString());
            return View("PeopleView", vmnew);
        }


        public ActionResult PeopleView()
        {

            List<Person> staff = new List<Person>();
            staff.Add(new Person(1, "Sam Brown"));
            staff.Add(new Person(2, "Bob Right"));
            staff.Add(new Person(3, "Henry Dune"));

            PeopleViewModel vm = new PeopleViewModel(2, staff);

            return View("PeopleView", vm);

        }
    }
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

 

ScreenShot

image

 

As always here is a small demo project. Enjoy

http://dl.dropbox.com/u/2600965/Blogposts/2011/11/SelectMVC.zip

Current Work

JQuery Not Working With FireFox

For those of you that follow my blog, or know me you will know that I am mainly a WPF/WCF kind of guy, but I Do love ASP MVC, and thought of a tool that I wanted to use, and thought it would be best served as a web based app, so without further ado I set about getting stuck into some ASP MVC and JQuery.

All was going beautifully, my JQuery was coming along leaps and bounds, and was working in Internet Explorer/Firefox/Chrome, and then I changed something.

Suddenly JQuery stopped working entirely in Firefox, despite the fact that the Firebug FireFox addin reported no errors at all, and JQuery worked just fine in Internet Explorer and Chrome. This really hacked me off, and I annoyed my web developer colleague to death on this, and still nothing.

So I messed around for a while and worked out that to my surprise Firefox is far more finickity about how you declare you Javascript imports.

I was doing this

<script src="/Scripts/jquery-1.4.2.min.js" type="text/jscript"/>

Which as I say worked fine in IE/Chrome, but did not in Firefox, but alas no warnings either. After some Googling, I found a post on StackOverflow, that said for Firefox to work you must conform to the correct XHTML schema definition which means you must declare the script import with a correct end tag, like this:

<script src="/Scripts/jquery-1.4.2.min.js" type="text/jscript"></script>

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }But still no banana in Firefox…hot damn what is going on, still all was fine in IE and Chrome most peculiar.

Turns out the MIME time is all so very important for Firefox, you need to declare the import as follows, and all is then good:

<script src="/Scripts/jquery-1.4.2.min.js" type="text/javascript"></script>

I found this post to be pretty useful in determining what MIME types are supported by the various browsers:

http://krijnhoetmer.nl/stuff/javascript/mime-types/

Here is the relevant parts

text/javascript

Opera 7.54+
IE 5+
Firefox 1.0.7+
Safari 2.0.3+
iCab 3 Beta 394
Camino 2006021400

text/jscript

Opera 7.54+
IE 5+
Safari 2.0.3+

Ok its probably an old post, but put me on the right track.

Hope this post and the one above I linked to helps you not get stung like I did.
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Current Work

Just A Quick Note To Say What I am Up To

Its been a while since I did any serious blogging, I have not forgotten about my blog, far from it, I have just been quite tied up writing up articles of late, Cinch V2 kept me pretty occupied.

But anyway here is a list of things that I am up to, right now

Main Focus

Being a dad

Secondary Focus

So what else am I up to, well I am in the middle of creating a pretty large ASP .NET MVC project that is a tool that I think may help many developers. I don’t want to say too much about it, but I honestly think it will be a really really useful tool. What I can say is that you will be able to interact with the website right from inside VS2010 using a VS2010 addin, and that I will be releasing the code onto Codeplex, as another opensource project, and I will write it all up over at codeproject anyway, as the web site design uses some nice AJAX JQuery along with ASP .NET MVC, which I think might interest some folk by itself, and I shall also be talking about how to create a VS2010 add in, and of course I will explain what the tools job is, and hopefully you lot will see that it could be useful to you too.

And Finally

I have also been asked to be a technical reviewer for a friends book, which I will commence work on next week.

 

So as you can see I am still busy, its just that I tend to work on larger things these days, and that takes up more time, which leaves less time for blogging.

I do have a plan for a IPhone like control which I will write for WPF, when I find a spare minute.

 

Anyway just wanted to let you all know that, I am doing stuff, and that is what I am doing.

Current Work, MVVM, WPF

Cinch (Again)

As my last post on Cinch indicated I fixed a lot of stuff in the latest drop, there 1 or 2 areas where I forgot to fix things (though the code still works, but could have been improved, so I improved it).

I then had major headaches with SVN/Codeplex source code getting corrupted whilst I was trying to update codeplex, so I struggled with that for a long time on Saturday 08/05/2010.

So if you downloaded Cinch again, I would urge you to please download and use the latest drop where the codeplex realease tab states “All Fixed”.

As the comment indicates this has all fixes and is correct source control (SVN) wise.

I am now working on Cinch V2 which I think it going to be a much better API to work with.

Enjoy Cinch V1 for now, Ill keep you all post Re: Cinch V2.

There will also be a new demo app for Cinch V2 for both WPF and SL.

Current Work, MVVM, Significant Projects (Shareable), WPF

Cinch (My MVVM framework) Part 4 is out

I just published part III of my MVVM framework series over at http://www.codeproject.com .

Here is the link

http://www.codeproject.com/KB/WPF/CinchIV.aspx

 

This time I talk about

Developing Models Using Cinch
Developing ViewModels Using Cinch

    * Choosing a ViewModel Base Class
    * ViewModelBase Class
    * How To Use The Exposed Services
          o EventLogger service
          o MessageBox service
          o Open File service
          o Save File service
          o Popup window service
    * Background Tasks
    * Mode Support

 

Enjoy