Click here to Skip to main content
Click here to Skip to main content

OOP in ASP.NET MVC 3.0 despite of the Razor

, 23 Feb 2011 CPOL
Rate this:
Please Sign up or sign in to vote.
OOP is still alive, and we can learn Razor (us) to behave this way...

Index

  1. Preface
  2. MVC 3.0 Razor as an OOP killer
  3. The goal to have solution of dreams: OOP in ASP.NET MVC 3.0 (Razor)
  4. Implementation of the OOP in ASP.NET MVC 3.0 (Razor)
  5. Summary (and download)
  6. Example: ListView (new 24.2.2011)

 

I. Preface (top)   

All examples and the Catharsis framework guidance are available here.

This article extends  my previous story: The OOP Approach on MVC UI - System.Web.UI.Controls. You should take a look, because here I tried to skipp what was written there...

This article is intended as an complete overview 1) how we should NOT use MVC 3.0 Razor engine and 2) how we should USE the MVC 3.0 Razor engine. While the topic is complex and wide, I decided to put it all together in one place, inside one story. I believe that if reader can have everything summarized in one paper, it will simplify the understanding to my blames (what is inappropriate) and to my suggestion (how to correctly and effectively use Razor)

Everything is based on intensive 3 years experience with ASP.NET MVC. All our knowledge comes from currently 5 larger projects, which are based on the Catharsis framework. Its latest version on http://catarsa.com is the powerful extract of our experience, built on many useful design patterns and best practices.

To get the fully working example to this article take it here, Firm.Example.zip 

 

II. MVC 3.0 Razor as an OOP killer (top)  

The Razor and ASP.NET MVC 3.0 are already here. I have investigated and read some stuff about it. And became sad. Does someone remember ages when we used to code in C#? when OOP with inheritance, encapsulation and polymorphism was the saint grail? Are we all using VS 2010? Do we like the intellisense? Type safety? compile time checks?

Recently, I was working with a very sharp knife in the kitchen. In a moment an accident have happened, and I felt the pain (the bloody story should be censored). BUT! There is a question: Who is guilty? The knife? The TOOL? Or the user - me? Or better, the way I used it?  

The problem: S# 

What is S#? see example and then you will get the answer S# == Spaghetti and unSafe code. Let's have a look on the main features which you will find in almost every article about ASP.NET MVC 3.0 and Razor.  

I.
@ViewBag.Title
    // the abbr. coming with "dynamics" for a ViewData["Title"] 

Is the dynamic what is .NET 4.0 about? When we start to use that, it could be funny and sexy! But the more code with such 'dynamic references' in our application will be, the less we will remember them. And intellisense, Resharper, compiler ... NONE will help us!

II.
@RenderPage("~/Controls/Home/Home.cshtml", "Hello", 4, false, new { id = 1})
    // the way how to add a "Control" on the View 

Not only the part , "Hello", 4, false, new { id = 1} is in fact params object[] data. Yes in .NET everything is object, but this is too much... Well, and see the first parameter: "any/string/path/to/some/resource". Do I have to mention type safety for above statement? The .NET 4.0 and strings which are evaluated only during the run-time?

III.
<p>Hello
@if(ViewBag.IsFriend) {
    <b>Friend</b>
} else {
    <i>Visitor</i>
}
</p>

This is the mixture of the HTML and script code. Much more better then in MVC 2.0, but still not so clear when your application is growing.

IV.
ASP.NET MVC 1.0:
<%= "<br />" %> // rendered result was always "<br />"
ASP.NET MVC 2.0:
<%= "<br />" %> // rendered result was "<br />"
<%: "<br />" %> // rendered result was "&lt;br /&gt;"
ASP.NET MVC 3.0: (Razor)
@("<br />")     // rendered result is always "&lt;br /&gt;" 

So in the first version, nothing was Encoded (trust me, it was painful). Second edition allowed to decide, whether to encode or not. And the current Razor view engine? Do what ever you want, the result will be encoded. (Unless you return the HtmlString).

So you have to write more:

@(new HtmlString("<br />"))
// or use or create some encapsulation method X:
// public virtual HtmlString X(string text) { return new HtmlString(text); }
@X("<br />")
@X("some string") is my preferred, very short approach. Expects that you have base class for your Razor engines (which is not should but rather must in flexible architecture). Other hacks are even uglier...
V.
@Html.DropDownList(ViewBag.Source, "Key", "Value", new { "Me", "We"}) 

HtmlHelper 

The stand-alone design failure HtmlHelper is still here:

Do you need to change the result of this method, the rendered HTML text? you can have to copy paste the code and create new method! The same goes for parameter extending. (static methods as the pillar of the ViewEngine? == S# )

Type safety suffers here the most... is the third string parameter 'key' or 'value'? Named or default parameters (C# 4.0) will not solve it, because there is NO way how to force to use them...  

S#  ==  Spaghetti & unSafe code   

S#, Spaghetti and unSafe code is presented everywhere as the MVC 3.0 essence, as the new 'Razor style'.  

All above, is simply very ugly workaround we get with the Razor engine. In fact this is only the way its used. We do not have to go this way.  

The Razor Engine   

The Razor engine, when used gently, could really make our code simpler, readable while still type safe and based on OOP. We will see more soon...

The Razors's nature is to REDUCE code. It should help us to be more effective. But there is no NEED to write in S# or to introduce type unSafety e.g.:

1) Razor itself is cool! see the Home/Index.cshtml

@model IHomeModel
@{ Layout = LayoutRich; }
@RenderControl("Home/Home.cshtml")

2) MVC 2.0 is verbose. see the Home/Index.aspx

<%@ Page Language="C#" MasterPageFile="~/Views/Masters/RichMaster.Master" Inherits="ViewPageBase<Models.IHomeModel>" %>
<%@ Register TagPrefix="cwc" TagName="Home" Src="~/Controls/Home/Home.ascx" %>
<asp:Content ID="Content1" ContentPlaceHolderID="cphHead" runat="server" />
<asp:Content ID="Content2" ContentPlaceHolderID="cphContent" runat="server">  
    <cwc:Home runat="server" />
</asp:Content>

Both snippets are doing the same

 

 

III. The goal: to have solution of dreams: OOP in ASP.NET MVC 3.0 (top

OK, we mentioned "the ways of using Razor" which end up in the S#.

Basic requirements to avoid S#

So what should we demand? What we would like to gain? How should our code in Razor look like to fit these requirements:

  • to be Effective (write only what is needed)
  • to be Readable (mixture almost always leads to lose of the reader's concentration)
  • to be Type safe (if not in design time, at least at compile time)
  • to have Solution for both, the Razor and older ASP.NET view engine (.aspx, .ascx)
System.Web.UI.Control

The underlying implementation have to be based on fully typed objects. And because we are in ASP.NET world, let's uncover the secret right now: the System.Web.UI.Control is the chosen one.

Yes, the old-fashioned System.Web.UI.Control objects family. Because this concept is one of the best things in the web forms (if used gently and correctly). These objects (Controls) will met the OOP essence

  • Inheritance
  • Encapsulation
  • Polymorhpism

And that will allow us to extend them, reuse code, hide inner implementation and manipulate them as needed (e.g. Table can consume only ITableChild - TableRow, TableHead...)

Nice to have

And we will ask for more.

  • Fluent syntax
  • No dependency on third party tools, libraries (if not the Catharsis framework Smile | :)
  • Managed HTML Encoding

...and maybe some other added values as a by product...

Examples of the final usage

simple HTML syntax

Let's write down some code snippets, which will show the target appearance. The Razor syntax could look like this:

@AddControls(
    new Div("myClass")
    {    
        new Image(picturePath)
            .SetAlt("MyPicture"),
        new Span
        {
            new Literal("This is my picture")
        },
    })

the HTML result

<div class="myClass">
  <img src="picturePath.jpg" alt="MyPicture" />
  <span>This is my picture</span>
</div>

The same should be working in .aspx engines

 <%= AddControls(
    new Div("myClass")
    {    
        new Image(picturePath)
            .SetAlt("MyPicture"),
        new Span
        {
            new Literal("This is my picture")
        },
    }) %>
Compound controls MyControl

We should have some compound Controls which will encapsulate some functionality. E.g. they will decide if they will render <div> or <input> element. Of course, decision will be done on strongly typed parameter

@AddControls(
    new Div("myClass")
    {
        new MyControl("alignRight")
            .SetText(Model.Item.FirstName)
            .SetInputName("FirstName")
            .SetReadOnly(Model.IsReadOnly),
    })

And with a bit of Expression parsing:

@AddControls(
    new Div("myClass")
    {
        new MyControl("alignRight")
            .SetSourceProperty(() => Model.Item.FirstName)
                // The FirstName will be read from this expression
                // as well as the 'string' value for Text property
            .SetReadOnly(Model.IsReadOnly),
    })
Fluent example 

Do you remember the S# syntax for if statement? Let's demand more!

@AddControls(
    new Paragraph
    {
        new Literal("Hello"),
        Model.IsFriend // if
            ? new Bold("Friend")
            : new Italic("Visitor"),
    })
Entity handling

In cases that we have a framework we usually have implemented master pages and do concentrate only on the Entity dependent implementation. Imagine that we have some CodeList entity, then we should demand this type of declaration:

@model ICodeListModel          
@this.CreateForm()

@AddControls(
    new Fieldset("w70p mh100 ", Str.Business.Common.Description)
    {
        new DefinitionList
        {      
            new TextOrInput().SetSourceProperty(() => Model.Item.Code),            
            new TextOrInput().SetSourceProperty(() => Model.Item.Name),            
            new CheckBox()
                .SetSourceProperty(() => Model.Item.IsVisible)
                .SetCssClassName(Str.Align.Left),            
            new TextOrInput(true)
                .SetSourceProperty(() => Model.Item.ID)
        }
    })
@this.CloseForm()

And this is the View with the CodeList rendered as a ListView. See that we are able to pass inner model:

@model IEntityModel<IPersistentObject, ISearch>
@AddControls(
    new ListView
    {
        ViewDataKey = "ListModel",
        FormSubmitButton = this.GetButton(Str.SearchFor.ActionReturnResults),
    }
)
goal summary 

I believe that right now you have some overall idea how should the final solution look like. We have to do these steps.

  1. Introduce the base control for our objects: VisualControl
  2. Introduce the IVisualControl interface, which will extend the power of the polymorphism.
  3. Inspect some VisualControl direct child Controls
  4. Introduce the ContentControl (fluent syntax, accepted child type restrictions)
  5. Inspect some ContentControl direct child Controls
  6. Implement AddControls() method on the RazorBase class, the base of all Razor views in our application.

well, let's start

 

 

 

IV. Implementation of the OOP in ASP.NET MVC 3.0(top)

The complete, working solution you will find in this download. Here I will describe only the main parts to reduce the snippets size

VisualControl

VisualControl will be descendant of the System.Web.UI.Control. And to get more functionality, it will be derived form the ASP.NET MVC ViewUserControl.

The ICoreModel is expected to be the base IModel of your application, which all Models do implement.

public abstract class VisualControl<TModel> : ViewUserControl<TModel>, IVisualControl
    where TModel : class, ICoreModel
{
    // #region HtmlString

    // This is a gateway for a Razor (or .ascx) view engine.
    // @AddControls() will call this ToHtmlString()

    public virtual string ToHtmlString()
    {
        var builder = new StringBuilder();
        var writer = new HtmlTextWriter(new StringWriter(builder));
        RenderControl(writer);     // see below how it is implemented
        return builder.ToString();
    }
    // #endregion HtmlString

    // if overridden in child Controls, it provides the tag name e.g."div"
    // end decides whether the begin and end tags will be 'automatically' rendered
    // if left empty, no tag is (by default) rendered, e.g. Literal or some CompoundControl

    protected virtual string TagName { get { return string.Empty; } }

    // #region Render

    // explicitly implemented method, to allow simple call to all child controls
    // (while still a bit 'hiding' it from public VisualControls methods)
  
    void IVisualControl.OnPreRender(EventArgs e)
    {        
        OnPreRender(e); // the way how to "call children" and forc
    }
    // this is a trick! the essence of this solution
    // this method is called whenever a new Control is added into the Controls collection.
    // but it could happen in time, when all needed properties are not provided yet
    // e.g. UrlHelper, ViewContext...
    // So, when a control is added, this overriden method (doing nothing) is called.
    // the base implementation will be called manually later...

    protected override void AddedControl(Control control, int index) { } // hide

    // This is a call to all children. It is managed by RenderControl (until overriden)
    // and it means, that at the moment of call, all needed properties
    // are already set, e.g. UrlHelper, ViewContext
    // That mean, that right now, we can call the base.AddedControl() implementation
    // to profit form its powerful implementation
    
    protected virtual void InitControls()
    {
        foreach (var c in Controls)
        {
            base.AddedControl((Control)c, 0); // it will provide child with lot of stuff
            c.Url = Url;
            c.ViewContext = ViewContext;
            c.OnPreRender(new EventArgs());
        }
    }
    // This method is the old fashioned RenderControl().
    // Its implementation here:
    // 1) mimics the Binding - the call InitControls()
    // 2) Rendering
    // - begin tag, content (children), end tag

    public override void RenderControl(HtmlTextWriter writer)
    {
        InitControls();
        RenderBeginTag(writer);
        RenderContent(writer);
        RenderEndTag(writer);
    }
    // If descendant Control returns TagName....
    protected virtual void RenderBeginTag(HtmlTextWriter writer)
    {
        if (TagName.IsNotEmpty())
        {
            writer.Write(Environment.NewLine);
            writer.WriteBeginTag(TagName);
            Attributes.Render(writer);
            writer.Write(HtmlTextWriter.TagRightChar);
        }
    }
    // all child controls are already Initiated,
    // provided with UrlHelper, Model, ViewContext...
    // so they can be rendered

    protected virtual void RenderContent(HtmlTextWriter writer)
    {
        foreach (Control control in Controls)
        {
            RenderChild(writer, control);
        }
    }
    protected virtual void RenderEndTag(HtmlTextWriter writer)
    {
        if (TagName.IsNotEmpty())
        {
            writer.WriteEndTag(TagName);
        }
    }
    // this method is intended to be overridden if needed...
    protected virtual void RenderChild(HtmlTextWriter writer, Control control)
    {
        control.RenderControl(writer);
    }
    // #endregion Render 

IVisualControl

This interface will simplify polymorphic operations. For example it will help us to act with any control without generics.

public interface IVisualControl :
    IComponent,
    IParserAccessor,
    IUrlResolutionService,
    IDataBindingsAccessor,
    IControlBuilderAccessor,
    IControlDesignerAccessor,
    IExpressionsAccessor,
    IViewDataContainer,
    IAttributeAccessor,
    INamingContainer,
    IUserControlDesignerAccessor,
    IFilterResolutionService
{
    string ID { get; set; }
    IUrlHelper Url { get; set; }
    ViewContext ViewContext { get; set; }
    void OnPreRender(EventArgs e);
}
Why so many interfaces? Well, every System.Web.UI.Control has collection of Controls which must be of type System.Web.UI.Control. Because we would like to operate with interfaces (IVisualControl, ITableChild...) and there is now IControl (implemented in core MS lib System.Web) we simply declare as many interfaces implmented by Control as possible to make it obvious: if you want to implement IVisualControl - use the VisualControl as a base class. Its hack, but legal, fixing the missing features...

This interface has two mayor reasons

  1. supports the binding (parent can pass Url, ViewContext and call Prerender)
  2. can be used as a filter for excepted children type (Table can restrict children to ITableChild : IVisualControl).
VisualControl children

There are some controls which are derived directly from the VisualControl. These do not have children:

  • Literal (an object representing any Text inside HTML elements)
  • Break <br />
  • Horizontal <hr />
  • ListView (powerful control, expecting IListModel)

Their implementation is (except of the ListView) very simple:

Literal
public class Literal : VisualControl<ICoreModel>
{
    // constructor
    public Literal(string text = null)
    {
        SetText(text);
    }
    // properties
    public virtual string Text { get; set; }
    public override void RenderControl(HtmlTextWriter writer)
    {
        writer.WriteLine
        (
            HttpContext.Current.Server.HtmlEncode(Text)
        );
    }
    // Set
    public Literal SetText(string text)
    {
        if (text.Is())
        {
            Text = text;
        }
        return this;
    }
}
Break
public class Break : VisualControl<ICoreModel>
{
    // render
    public override void RenderControl(HtmlTextWriter writer)
    {
        writer.WriteBreak();
    }
}

That's enough, until now, to start to use the above controls this way:

@AddControls(
    new Literal("Text before break"),
    new Break(),
    new Literal()
        .SetText("Text after break")
    )

And to get this HTML result

Text before break
<br />Text after break

ContentControl

The abstract VisualControl provide base implementation for Controls without need to extend them fluently (e.g. break <br />). For controls, which requires more settings to render more complex content, there is a derived class ContentControl. It extends some base functionality:

The System.Web.UI.Control has built-in collection for HTML attributes. Very important feature for us is, that we can append, extend and remove attributes using this collection. And what's more, when we ask this collection to be rendered (see above) it is ENCODED. So we do not have to care!

In ContentControl we only simplify the access to this collection with 2 methods SetAttribute(name, value) (the fluent syntax support) and GetAttribute(name).

ContentControl introduces support for the syntax as we know from List (by implementing two methods: GetEnumerator and Add()):

IList<string> coll = new List<string> { "My", "Name", "Is"}

The ContentControl also introduces the filter, restriction for a type, which can be used for its children (where TChildControl : IVisualControl). Already noted Table control can be this way restricted to accept children of a ITableChild type only.

And there is finally the ContentControl definition.

public abstract class ContentControl<TModel, TChildControl, TContentControl> : VisualControl<TModel>, IEnumerable
    where TModel : class, ICoreModel
    where TContentControl : ContentControl<TModel, TChildControl, TContentControl>
    where TChildControl : IVisualControl
{
    // #region Add Controls
    public virtual TContentControl AddControls(params TChildControlcontrols)
    {
        foreach (var control in controls)
        {
            Add(control);
        }
        return this as TContentControl;
    }
    // this two below methods are the only needed implementation
    // to provide the syntax similar to list initialization:
    // new DIV { control1, control2, control3 }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return Controls.GetEnumerator();
    }
    public virtual void Add(TChildControl control)
    {
        Controls.Add(control);
    }
    // #endregion
    
    // attribute setter
    public virtual TContentControl SetAttribute(string attributeName, string value)
    {
        base.SetAttribute(attributeName, value);
        return this as TContentControl;
    }
    // attribute getter
    protected virtual string GetAttribute(string attributeName)
    {
        if (attributeName.IsNotEmpty())
        {
            return Attributes[attributeName];
        }
        return string.Empty;
    }
}
ContentControl children

One of the simplest but very important ContentControl children is the PlaceHolder

 public class PlaceHolder : ContentControl<ICoreModel, IVisualControl, PlaceHolder> { } 

Yes that's all implementation. This control can be instantiated and can contain other Controls, while not rendering any HTML. Cool.

Another simple control is the DIV:

public class Div : ContentControl<ICoreModel, IVisualControl, Div>
{
    // constructor
    public Div(string cssClassName = null)
        : base(cssClassName) { }
    // properties
    protected override string TagName
    {
        get { return Tag.Div; }
    }
}

That's it. Div can consume any IVisualControl. By overriding the TagName the base VisualControl implementation is used: Open tag is rendered, all attributes, content, end tag.

Similar way other controls can be created. Even for complex controls we will use the same infrastructure. for more details download and see example.

RazorControl.cs - base class for pages.cshtml

Finally we have to place our control(s) on a view engine page. We need to learn Razor (or .ascx Control) how to use them. For this purposes we will implement the AddControls() method. It will be placed in the RazorControl class which is the base for every Razor view in our application.

public abstract class RazorControl<TModel> : WebViewPage<TModel>
    where TModel : class, ICoreModel
{
    protected virtual HtmlString AddControls(params IVisualControlcontrols)
    {
        var holder = new PlaceHolder
        {
            ViewContext = ViewContext,
            ViewData = new ViewDataDictionary<ICoreModel>(Model),
            Url = Url,
        };
        holder.AddControls(controls);
        return new HtmlString(holder.ToHtmlString());
    }
}

And that's it. From this moment we can live in Razor view engine, while still doing the real OOP. This will be working right now:

@AddControls( new Div { new Literal("Hello World") } )

 

 

 

V. Summary and download (top)  

I believe that the above article successfully explained how we can return the OOP, the ASP.NET Controls back on the track. Even in the MVC 3.0 Razor engine environment. MVC 3.0 Razor is cool, but the Type safety, intellisense and compile checks are cooooler. If we will succeed to put that all together we WILL gain a lot.

As in my very first note about the knife and its incorrect usage - Razor is a tool, which, in correct hands with the gentle intentions, can do a lot of job. In rude hands, it could and probably would do an unintended damage...

Appendix: S# fixed 

And how we can fix all the 'blamed! S# code

I.
@Model.Title // where IModel simply implements: string Title { get; }  
II.
@RenderPage("~/Controls/Home/Home.cshtml", "Hello", 4, false, new { id = 1})
@AddControls(new Home("Hello").SetCount(4).SetIsReadOnly(false).SetId(1))
III.
@AddControls(
    new Paragraph
    {
        new Literal("Hello"),
        Model.IsFriend // if
            ? new Bold("Friend")
            : new Italic("Visitor"),
    }) 
IV.
@X("<br />") // to get "<br />"
V.
@AddControls( new ComboBox().SetSourceProperty( () => Model.Item.Country)) 
 // observe example, this is really enough ... 

All downloads are available here.    

 

Appendix

After discussion below this article I have to make sure, that also this is still working:

<fieldset>
  <legend> my legend </legend>
  <div class="body">
  @AddControls( new ComboBox().Set.....
  @AddControls( new TextBox().Set.....
  </div> 
<fieldset> 

Other words: The Controls allows you to take out a part which is by your decision good to be accessed as object. If you would like to have the wrapped HTML placed as the tags (H1, DIV above)... it is still there and working. 

Once, you will firstly see, feel or undertand the advantage of Controls as objects, then you will move to this:

@AddControls(
  new Fieldset("my legend") // the LEGEND is encapsulated for you
  {
    new Div("body") //....
    ...

Isn't it cool?!? Imagine, what more you can do with objects, instead of the strings...

 

 

 

V. Example: ListView (top) (new 24.2.2011)

 After all the notes and comments I decided to show you some real example. All above can be used on any project, without need to use any external library (just few coding). The pictures are taken from Catharsis Firm.Example, where it is already implemented. But the point is the solution, the approach - not the need to download and reference some .dll

I  would like to thank you to all of you, who spent your time to append note, disagreement or blame, and of course to them, who succeeded to see - what that all is about. Without the feedback, I can hardly give you more... THANKS

Well the next picture shows the CONTROL ListView.  

ListViewCode.png
 

As you can see it has "few" lines, which set the basic ListView functionality. Code has about 500 rows, but it follows the tremendous LAW for the Coding standards by Lance Hunt.

(The aim is not to save the rows/lines of code. Our target is to save coding. The code itself must be readable, understandable and maintainable. Lance Hunt did great job. We should follow it and from my (our) experience - it should be a LAW. It will help anyone to geti in the project very quickly)

Anyhow, now we have the control. It is used on the shared ListView.cshtml, and is reused for every entity:

 List_View.png

Maybe until now, you can think, that you can do it your way, with htmlhelper or with Razor. To help you to have some idea about the result, there are some tables (for different entities) rendered by this control.

 Tables.png

The ListView is very powerful. It has paging, sorting, navigation to detail, to edit, delete... it is able to convert bool to Checkboxes... and many more.

But what if there is a new demand? to have special cell (TD). The TableCell (control) should simply render different HTML. And that's the place where OOP brings you, what  anythinge else can hardly give you (sorry for the strict naming of things, but try to do it other way...).

 ComplexListView.png

As you can see, we reused all the ListView functionality, and created a baby: ComplexListView. We have to change only one (ONE == 1) piece, the TableCell. And there is a result. Only one method is overriden. (Can you do the same over static Extension methods?)

 ComplexResult.png

Summary of this example: While the above article mostly tried to show you advantages of OOP on the simplest stuff, this example targets the top level of Control usage. But behind of this, there are the bricks, the building blocks: TD, TR, TBODY... represented by objects - controls TableCell, TableRow, TableBody.... And these bricks-objects allow you creating and extending any HTML part, while still living in object representation of the HTML elements. 

 


Enjoy the OOP, try to taste Catharsis 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Radim Köhler
Web Developer
Czech Republic Czech Republic
Web developer since 2002, .NET since 2005
 
Competition is as important as Cooperation.

___

Comments and Discussions

 
GeneralSeperb PinmemberP_A_118-May-12 1:09 
QuestionNice Article Pinmemberzyck20-Feb-12 6:00 
GeneralOn a nicer note... PinmemberStacey Thornton22-Feb-11 14:17 
General[My vote of 1] Adding to the problem. [modified] PinmemberStacey Thornton22-Feb-11 13:45 
GeneralRe: [My vote of 1] Adding to the problem. PinmemberRadim Köhler23-Feb-11 5:03 
GeneralS# is nothing common with spagetti code Pinmembermarisks15-Feb-11 19:38 
GeneralMy vote of 2 PinmemberMarek Konieczny13-Feb-11 3:23 
GeneralRe: My vote of 2 PinmemberMarek Konieczny25-Feb-11 5:59 
GeneralRe: My vote of 2 PinmemberRadim Köhler25-Feb-11 7:37 
GeneralRe: My vote of 2 PinmemberMarek Konieczny25-Feb-11 23:19 
GeneralRe: My vote of 2 PinmemberRadim Köhler25-Feb-11 23:49 
GeneralRe: My vote of 2 Pinmemberjustinctree10-Aug-11 12:05 
QuestionWhy not just use Spark? PinmemberDaniel Gidman9-Feb-11 11:59 
AnswerRe: Why not just use Spark? PinmemberRadim Köhler10-Feb-11 6:04 
GeneralRe: Why not just use Spark? PinmemberDaniel Gidman10-Feb-11 8:21 
GeneralMy vote of 2 Pinmembervaygas7-Feb-11 12:37 
GeneralRe: My vote of 2 [modified] PinmemberRadim Köhler8-Feb-11 5:11 
GeneralMy vote of 5 Pinmemberandrew45825-Feb-11 15:14 
GeneralMy vote of 1 PinmemberThomas Eyde4-Feb-11 1:58 
GeneralRe: My vote of 1 PinmemberRadim Köhler4-Feb-11 2:42 
GeneralRe: My vote of 1 PinmemberThomas Eyde4-Feb-11 3:10 
GeneralRe: My vote of 1 [modified] PinmemberRadim Köhler4-Feb-11 3:17 
GeneralRe: My vote of 1 PinmemberThomas Eyde4-Feb-11 3:42 
GeneralRe: My vote of 1 PinmemberRadim Köhler4-Feb-11 4:02 
Generaltrendz PinmemberMember 394053-Feb-11 17:55 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.141216.1 | Last Updated 24 Feb 2011
Article Copyright 2011 by Radim Köhler
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid