1 0
post icon

Binding to a ListControl the Lazy Way

After the Enums the Lazy Way post I was left thinking about this TextValueItem class I created. It seemed to have much more potential. So I began to think of the following piece of code I stumble upon daily:

            cbPerson.DisplayMember = "Name";
            cbPerson.ValueMember = "Id";
            cbPerson.DataSource = persons;
            cbPerson.DataBind(); //On Web Scenarios

We have to bind all sorts of different entities and objects to Checklists, listboxes, comboboxes and the like on Windows and Web applications. So I figured I could use the TextValueItem class and do some nice things to save time, effort and to increase code readability. The solution is to create an attribute and some extensions to easily bind a List to ListControls either on web or windows apps.

The Solution

The solution is quite straightforward. I just created a TextValueAttribute that is applied to your entities/classes. Then I created a few extension methods to provide syntactic sugar for usage scenarios. In the end all IEnumerable<T> objects when T has the TextValue attribute, could be converted to a List<TextValueItem> and then be bound to any control that inherits from ListControl (for both System.Windows and System.Web namespaces).

Here’s the Attribute Code:

    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
    public class TextValueAttribute : Attribute
    {
        public TextValueAttribute(string textProperty)
            : this(textProperty, "Id")
        {
        }

        public TextValueAttribute(string textProperty, string valueProperty)
        {
            TextProperty = textProperty;
            ValueProperty = valueProperty;
        }

        public string TextProperty { get; private set; }
        public string ValueProperty { get; private set; }
    }

Here we simply define which properties of a given class will serve as Text and Value providers for binding to ListControls. The Usage is quite simple as ilustrated below.

    [TextValue("Name")] //This asumes "Id" as the value property, as is the case in this class.
    public class Person
    {
        public Person(int id, string name)
        {
            Name = name;
            Id = id;
        }

        public string Name { get; set; }
        public int Id { get; set; }
    }

Then I created a class containing a few extension methods for IEnumerable&lt;T&gt; and for List&lt;TextValueItem&gt;. These will enable all our classes decorated with TextValueAttribute to be binded really easy.
Here’s the code for all extensions:

    public static class TextValueItemExtensions
    {

        public static List<TextValueItem> GetAsTextValueItems<TEntity>(this IEnumerable<TEntity> list, string defaultText, string defaultValue)
        {
            List<TextValueItem> items = GetAsTextValueItems(list);
            items.Insert(0,new TextValueItem(defaultText,defaultValue));
            return items;
        }

        public static List<TextValueItem> GetAsTextValueItems<TEntity>(this IEnumerable<TEntity> list)
        {
            //Look for TextValueAttribute in type used in IEnurable.
            Type type = typeof(TEntity);
            object[] attributes = type.GetCustomAttributes(typeof(TextValueAttribute), true);
            if (attributes.Length == 0)
            {
                throw new ArgumentException(string.Format("Type '{0}' doesn't have the TextValue Attribute.", type.FullName), "list");
            }

            //Retrieve Information for binding.
            var attribute = attributes[0] as TextValueAttribute;
            PropertyInfo TextProperty = type.GetProperty(attribute.TextProperty);
            if (TextProperty == null)
            {
                throw new ArgumentException(string.Format("Type '{0}' has an invalid property name '{1}' for the Text field in the TextValue Attribute.", type.FullName, attribute.TextProperty), "list");
            }

            PropertyInfo ValueProperty = type.GetProperty(attribute.ValueProperty);
            if (ValueProperty == null)
            {
                throw new ArgumentException(string.Format("Type '{0}' has an invalid property name '{1}' for the Value field in the TextValue Attribute.", type.FullName, attribute.ValueProperty), "list");
            }

            //Return instances.
            List<TextValueItem> items = new List<TextValueItem>();
            foreach (var item in list)
            {
                items.Add(new TextValueItem(TextProperty.GetValue(item, null).ToString(), ValueProperty.GetValue(item, null).ToString()));
            }
            return items;
        }

        public static void BindTo(this List<TextValueItem> list, ListControl listControl)
        {
            listControl.DisplayMember = "Text";
            listControl.ValueMember = "Value";
            listControl.DataSource = list;
        }

        public static void BindTo(this List<TextValueItem> list, System.Web.UI.WebControls.ListControl listControl)
        {
            listControl.DataTextField = "Text";
            listControl.DataValueField = "Value";
            listControl.DataSource = list;
            listControl.DataBind();
        }

    }

These extension methods have a caveat, they have a dependency on both the System.Windows.Forms and System.Web assemblies, I cringed myself when I saw this, but flexibility comes at a price. In any case if your project is only Windows o Web, you could easily remove the extension methods for the type of application you’re not using.

Usage

So the usage is the same for both windows and web, you’d just do this:

            List<Person> persons = new List<Person>();
            persons.Add(new Person(1, "Héctor"));
            persons.Add(new Person(2, "David"));
            persons.Add(new Person(3, "Charles"));
            persons.Add(new Person(4, "Joan"));

            //Get All Persons
            persons.GetAsTextValueItems().BindTo(lbPerson);

            //Get All Persons and add new Item as default.
            persons.GetAsTextValueItems("[Select]", "0").BindTo(cbPerson);

And that’s it :) ….I hope it’s usefull to you!

Download VS2008 Project

Read full story »
post icon

Enums with localization the Lazy Way

So, I worked for a while in a codebase that has a ton of enums, they’re used to categorize a lot of data and to help define and apply a lot of  business rules. This might come as a surprise but, you’re not the only one that has wondered which is the best way to deal with enums, to localize them and display them easily on your presentation layers. In the project I mention we came up with a solution that involved storing enum values, names and descriptions for the UI in a table and we just queried that table when we needed to deal with the enums on the frontend.

That approach served us well, it’s probably a common thing to do, but a couple of weeks ago starting a new project and faced with the dilema again I found that now most things seemed rather wrong with the solution:

  1. For every use of a form with an enum we needed to query the database, and mind you there were a lot of enums and a lot of round trips to the database. So we had to implement a caching mechanism on our services for this (throwing more code to a problem anyone?).
  2. If the source had to be compiled again for enum changes, why would we keep their presentation data in a changeable and expensive to consult environment like the database, this seems overkill.
  3. Special care (A.K.A more code, A.K.A post it notes everywhere) had to be given to keeping the database and code representations of enums synched (yes, we gave a towel to each team member).
  4. We didn’t do almost any reporting on this application, it was pure operations, just a handful of reports here an there none with enums involved, then why the table at all?.

So I decided to use some T4 templates, reflection and xml to solve this problem in the new project. The solution in a nutshell is an xml file defining the enums, all the cultures that the application will support and just generate both the code and the resources of off the Xml, here it is.

The Xml File

The file defines among other things, the namespace for the code generation, the relative path to the project root where resources are to be saved, all the cultures a resource will be generated for and all enums.

<enums namespace="DevDo.LazyEnums">
  <resources relativePath="Resources" filename="Enums">
    <culture code=""/> <!-- NEUTRAL CULTURE-->
    <culture code="es"/>
    <culture code="de"/>
  </resources>
  <enum name="DaysOfWeek" summary="Exposes all days of the week.">
    <item name="Sunday" value="0" summary="Sunday" />
    <item name="Monday" value="1" summary="Monday" />
    <item name="Tuesday" value="2" summary="Tuesday" />
    <item name="Wednesday" value="3" summary="Wednesday" />
    <item name="Thursday" value="4" summary="Thursday" />
    <item name="Friday" value="5" summary="Friday" />
    <item name="Saturday" value="6" summary="Saturday" />
  </enum>
</enums>

The T4 Template

T4 template classes.

Classes on T4 template.

The three classes above are defined in the T4 template and used to load the xml definition file. The template loads the Xml file and outputs all enum types defined in it. It then creates a resource file for each culture specified using the following format: Enum.{culture}.resx. It verifies on creation that the entries to be added don’t exist, if they do, they’re left with their current values, if on the other hand there are entries in the resx file that aren’t defined in their corresponding enum, these are removed. Also all descriptions in the resource files are set by default to: “Resource value for enum item ({enum_value_name}) in Culture ({culture_name}) NOT SET.”

Usage and Syntactic sugar

  • To enable access to the description of an enum, an extension method Text() was created, which gets the description from the resource files depending on the UI Culture of the running app.
  • Also there’s a class for binding to combos/lists and that sort of Text-Value binding control. It’s called TextValueItem it has a method called GetAllForEnum<TEnum>() which returns a List<TextValueItem> with all possible values of the enum.

Here’s a few usage samples:


            //1 - Get text for enum with neutral culture
            Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
            Console.WriteLine("I wish today was {0}.", DaysOfWeek.Wednesday.Text());

            //2 - Get text for enum in other culture (spanish).
            Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
            Console.Write("{0} in spanish is ", DaysOfWeek.Wednesday.Text());

            Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("es");
            Console.WriteLine(DaysOfWeek.Wednesday.Text()+"\n");

            //3 - Get all possible enum descriptions as a TextValueItem list in spanish.
            Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("es");
            Console.WriteLine(TextValueItem.GetAllForEnum<DaysOfWeek>().JoinDescriptions(", "));

            //4 - Get the text for enum that doesn't have a resource value set (de - German).
            Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
            Console.Write("{0} in german is ", DaysOfWeek.Wednesday.Text());
            Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("de");
            Console.WriteLine(DaysOfWeek.Wednesday.Text());

The Output is:

1) I wish today was Wednesday.
2) Wednesday in spanish is Miércoles
3) Domingo, Lunes, Martes, Miércoles, Jueves, Viernes, Sábado
4) Wednesday in german is Resource value for enum item (Wednesday) in Culture(de) NOT SET.

Here’s the Code, give it a try and let me know if it helps you out.


Download VS2008 Project

Read full story »
post icon

ALT.NET: The Big Picture

By the time you read this, there’s probably some Google server failing for the first time ever while indexing developer blogs with the “ALT.NET” keyword. I’m going to save the poor souls dealing with it a lot of trouble and tell them it’s Sam Gentile’s goodbye codebetter and ALT.NET post the reason why they couldn’t hug an empty keg and watch some Yankees tears on Monday night. There…I said it.

What is the big deal you might ask? maybe you’re even asking yourself what’s this ALT.NET thing everybody is arguing about?

What is ALT.NET?

I personally found out about ALT.NET by reading Jeremy D. Miller, Scott Bellware, Jeffrey Palermo and Sam Gentile at codebetter.com. This “new” thing we have to lookup and make a wikipedia article for (any .net dev programming Assembly on the side interested?) Is meant to be a “movement” for .NET developers to embrace technologies and practices, no matter the source but how fit, elegant and simple they are for the task at hand.

Several explanatory posts can be found over the web, everyone is trying to find a satisfactory definition up to developers’ standards (uhmmm….good luck with that), but the most prolific place is codebetter where this whole thing started up it seems (not that I’m trying to take away credit, but one never knows). Below some excerpts from posts by codebetter bloggers:

David Laribee who coined the term in his post ALT.NET on April 10, 2007 says:

…What does it mean to be to be ALT.NET? In short it signifies:

  1. You’re the type of developer who uses what works while keeping an eye out for a better way.
  2. You reach outside the mainstream to adopt the best of any community: Open Source, Agile, Java, Ruby, etc.
  3. You’re not content with the status quo. Things can always be better expressed, more elegant and simple, more mutable, higher quality, etc.
  4. You know tools are great, but they only take you so far. It’s the principles and knowledge that really matter. The best tools are those that embed the knowledge and encourage the principles (e.g. Resharper.)

Jeffrey Palermo explained what he thinks the principles of ALT.NET are in his post What are the ALT.NET Principles – My Answer:

…These items apply the principles but are more directly applicable:

  • Read more than just MSDN magazine and MS Press.  Authors like Feathers, Fowler, Martin, Evans, etc have a lot to give (Knowledge)
  • Use Resharper.  It makes working with Visual Studio a (Joy).  But if another vendor comes along that does even better than JetBrains, consider switching
  • Use NUnit  over MSTest,  Subversion over TFS SCC,  Infragistics/Telerik over in-the-box controls,  RedGate over in-the-box SQL tools.  Each of these is a better alternative to that which Microsoft provides (Alternative Vendors).  Use NHibernate over hand-rolled stored procedures and especially over DataAdapter/DataSet, but if EntityFramework proves to actually be superior to NHibernate in a meaningful way, consider using it.
  • Use a responsible application architecture.  Don’t put everything in Page_Load like you see demonstrated at MSDN Events.  Use knowledge to create an application that can stand the test of time and not be rewritten every 2 years.  Deliver (high quality and excellence).
  • Automate every repetitive task; builds, tests, deployments, etc – excellence and joy

Sam Gentile defines ALT.NET and shows a list of Hot/Not (.NET?/ALT.NET) tools and practices in his The ALT.NET Moniker and List:

…it is really a way of life, a way of being a .NET developer on top of the CLR and favoring simplicity, testability, continous improvement, and tools that enable agility.

After reading these posts you’ll find that what is being said is quite simple and straightforward:

  • You should be constantly up to date on the practices of .NET software development and not limit yourself to Microsoft only content.
  • You should use the best tool for the job and not conform to out of the box .NET utilities from Microsoft all the time.
  • You should pay attention to architecture and thrive for simplicity and effectiveness.
  • The earth is not flat, and .NET is not the only platform that exists for delivering quality software solutions.
  • It’s all about leveraging the .NET Platform for effective software development!!!!

Now, replace all the “Microsoft” for [dev/language vendor] and “.NET” for [dev/language vendor's  development platform], what do you get? a good set of advice for everyone…..well that’s cool!!! but isn’t it obvious then? perhaps, too obvious?

Some might argue that as obvious as it seems, is something that is not applied throughout the industry…and well that’s true. But It’s tough, not everybody has the willingness to learn 2 new technologies, 7 new tools, 2 new frameworks and read 11 white papers in a month, read 100 blog posts a day, deal with a project that is a month late, start planning for a new project that should have been in production new year’s eve 2003, take care of the kids, pay the mortgage and  deal with a manager that failed Kinder Garden (TWICE!!!).

It’s hard, very very hard to keep up and frankly I don’t know how creating this new label for keeping up and being open minded is going to help us out doing it.

Read full story »
10. Jul, 2007