Extending Nettiers Part 2 – Adding an OnItemCommand

Posted by Monty on November 21st, 2008

A few days ago, I decided to try to extend the Repeater Control, by adding an OnItemCommand, like the System.Web.UI.WebControl. Simple I thought. Shouldnt be that hard I thought.

I couldnt have been more wrong.

I have learned alot with the whole experience. I have learned about event bubbling, the way that events get passed up the control tree till they are handled by their parents. Iv learned about the way that items that are nested will need to be databound for the event to be fired, even if the data is being shown on the page, you still have to explicitly call DataBind(); And I got some help from a random guy (who works for telerik!) on StackOverflow, thanks!

Basically, this is the way it works. When a user hits a button (Like a <asp:button) on the page, it will bubble up (OnBubbleEvent) on the ITemplate (In this case, the actual type of the ItemRepeater). That will do its magic, work out if its a CommandEventArgs, if it is, then bubble it up:


protected override bool OnBubbleEvent(object source, EventArgs e)
{
if (e is CommandEventArgs)
{
RepeaterCommandEventArgs args = new RepeaterCommandEventArgs(this, source, (CommandEventArgs) e);
base.RaiseBubbleEvent(this, args);
return true;
}
return false;
}

Taken from System.Web.UI.WebControls.RepeaterItem.OnBubbleEvent(object source, EventArgs e);

From there, the Repeater will intercept that, then process it:

private static readonly object EventItemCommand = new object();

protected override bool OnBubbleEvent(object sender, EventArgs e)
{
bool flag = false;
if (e is RepeaterCommandEventArgs)
{
this.OnItemCommand((RepeaterCommandEventArgs)e);
flag = true;
}
return flag;
}

protected virtual void OnItemCommand(RepeaterCommandEventArgs e)
{
RepeaterCommandEventHandler handler = (RepeaterCommandEventHandler)base.Events[EventItemCommand];
if (handler != null)
{
handler(this, e);
}
}

public event RepeaterCommandEventHandler ItemCommand
{
add
{
base.Events.AddHandler(EventItemCommand, value);
}
remove
{
base.Events.RemoveHandler(EventItemCommand, value);
}
}

This is where the fun starts. First off, in the RepeaterItem source code, you cannot call:

RepeaterCommandEventArgs args = new RepeaterCommandEventArgs(<strong>this</strong>, source, (CommandEventArgs) e);
base.RaiseBubbleEvent(this, args);

because this refers to a RepeaterItem, which, in my case, it is not because its a Nettiers generated RepeaterItem. So you have to go off and create your own CommandEventArgs. If you create your own EventArgs, the event handler RepeaterCommandEventHandler wont work, because its not of the type RepeaterCommandEventArgs. Which is a pain in the arse!

Once you have created the EventArgs and the event handler though, its fairly simple from there – you just modify the Reflector’ed code (From the RepeaterControl), to get it to handle your custom Repeater Item’s event, and not the RepeateItem default event which you cant even call!

But your not done! I found out that the command wont get called when someone clicky’s on it, because you havnt called DataBind(); on the control, which explains some … oddities I spotted in the code when I was digging around inside the Repeater – I kept finding calls to “EnsureDataBound()” – which is called OnPreRender:

Note: I will provide code samples and Nettiers templates very soon, as soon as I have integrated my changes into Nettiers!

I am quite worried about the standard of coding these days

Posted by Monty on November 18th, 2008

Ok, this is going to make me sound like a really old fart, which im not! Honest!

I was reading the blog of a Microsoft developer, someone whos team owns the Framework Design Guidelines, someone who worked on the VS Code Analysis team, and worked on FxCop.

Sample from davesbox.com

He then later states:

Comment from DavesBox.com

Im sorry, but WHAT THE F**K? Your not a fan of defensive coding, but you want us to do it in framework classes? With your code sample above, if label is null, guess what happens to your code? You may not like defensive coding, so you are going to assume that all of your code samples will work?

SetLabelTextIfNotEmpty(null);
SetLabelTextIfNotEmpty(Label1);  // No instance

Please tell me how your code will react to this? I guarentee that it will throw a null reference exception, because, well im passing in null to your method!

ALWAYS CHECK FOR NULL!

Im sure this is a minor lapse on your part, Dave, and im sure your code does not usually reflect this – if we had someone on my team, coding like this, I would either insist they change the way they code, or I would shift them off my team. Not checking for simple things, like null, is a major lapse in coding. You simply cannot guarentee that it will not be null, and wishfull thinking and happy thoughts arnt going to change it.

Evolution of looping

Posted by Monty on November 17th, 2008

While im writing a new project using vs.net 2008, Resharper cropped up a nice helper, saying I should use a lambda expression on my code, which made me think about how looping has evolved…


for (int i = 0; i < all.Count; i++)
{
tagCount.Add(new TagCount(container[i].Count, container[i]));
}

foreach (Tag tag in container)
{
tagCount.Add(new TagCount(tag.Count, tag));
}

container.ForEach(delegate(Tag tag)
{
tagCount.Add(new TagCount(container.Count, tag));
});

container.ForEach(tag => tagCount.
Add(new TagCount(container.Count, tag)));

Iv always thought lambda’s were gimmicky, but I do have to admit, they do look fancy and makes things like what im doing easier.

Introduction to CSS Adapters – Label Control

Posted by Monty on November 5th, 2008

CSS Adapters in .net are rarely used, even though they are really powerful and can fix things like xhtml validation errors. This very quick sample will show you how to replace the <span> tags with a <div>

Create a class file, something like “LabelOverride.cs”, and put in the following:


using System.Web.UI;

namespace CSSAdapterTest
{
public class LabelOverride : System.Web.UI.WebControls.Adapters.WebControlAdapter
{
protected override void RenderBeginTag(HtmlTextWriter writer)
{
writer.RenderBeginTag(HtmlTextWriterTag.Div);
}
protected override void RenderEndTag(HtmlTextWriter writer)
{
writer.RenderEndTag();
}
}
}

Create a folder in the web application called “App_Browsers”, and create a .browsers file called “CSSAdapter.browser”, and enter in the following:


<browsers>
<browser refID="Default">
<controlAdapters>
<adapter controlType="System.Web.UI.WebControls.Label"
adapterType="CSSAdapterTest.LabelOverride" />
</controlAdapters>
</browser>
</browsers>

This basically tells asp.net to override the controlType’s renderer with the one you have specified.

Once you have done this, and when you build your application, all <span>’s will disappear and be replaced with <div>’s!

Extending NetTiers part 1

Posted by Monty on October 15th, 2008

Im a very big fan of NetTiers – its an excellent product, an amazing piece of code created by the community, it rapidly speeds up development and basically gets rid of all the boring faff that you have to do to create databases – all that select, insert and update statements etc etc etc.

I would like to do some minor improvements to the project thoguh – iv already experimented with ILMERGE’ing all of the Microsoft.Patterns dll’s into one (So you dont have 500 DLLs referenced in each project, and speeds up deployment). One thing id like to detail on this blog is how to implement a SeperatorTemplate (ala System.Web.WebControls.Repeater) on one of the generated UI Component’s repeaters…

For this demo, im going to be using the Nettiers 2.3.0 beta 1 release…

Firstly, to find out the actual code to include a SeperatorTemplate, by our good friend the Reflector has revealed that you need to create a property and an accessor for it like the following:

	private ITemplate m_seperatorTemplate;

	[Browsable(false)]
	[TemplateContainer(typeof(WebsiteItem))]
	[PersistenceMode(PersistenceMode.InnerDefaultProperty)]
	public ITemplate SeperatorTemplate
	{
		get { return m_seperatorTemplate; }
		set { m_seperatorTemplate = value; }
	}

(Side note – I know that prefixing member variables with m_ is a bad practice, but I want to keep to the standards of the NetTiers code, because in my opinion, having 2 coding standards is worse than having one “bad” one)

Once you have created this property, all you have to do is create the seperator when it creates the child controls, in CreateChildControls, replace the following:

	if (m_itemTemplate != null &amp;amp;amp;amp;&amp;amp;amp;amp; (pos % 2) == 0)
	{
		m_itemTemplate.InstantiateIn(container);
	}

with:

	if (m_itemTemplate != null &amp;amp;amp;amp;&amp;amp;amp;amp; (pos % 2) == 0)
	{
		m_itemTemplate.InstantiateIn(container);
		m_seperatorTemplate.InstantiateIn(container);
	}

What this basically does, is instead of just creating the template, it will create teh template AND the seperator template underneath it. You can fiddle this around to how you want. Just as a side note, you will want to add the m_seperatorTemplate’s instantiator in the 2 other references a few lines down where it creates the alternating item style and the itemtemplate (if there is no alternate provided).

Once you have done this change, a quick check of the page, and it seems to work fine and exactly how I had planned. The next step is to change the Nettiers codesmith project so this gets done automatically, and for every repeater in the project.

By looking at where the source file is living, and a lil experimenting, you have to change both TableRepeater.cst and ViewRepeater.cst that lives in the WebLibrary/UI directory, like the following:

        /// <summary>
        /// Gets or sets the Seperator Template
        /// </summary>
        [Browsable(false)]
        [TemplateContainer(typeof(<%=entityItem%>))]
        [PersistenceMode(PersistenceMode.InnerDefaultProperty)]
        public ITemplate SeperatorTemplate
        {
            get { return m_seperatorTemplate; }
            set { m_seperatorTemplate = value; }
        }

Note the replacing of the type with <%=entityItem%> so it automagically generates this for all types.

A small improvement on the code above (Check to see that a Seperator template has actually been set!) when inserting, and your CreateChildControls should look something like this:

	/// <summary>
	/// Called by the ASP.NET page framework to notify server controls that use composition-based implementation to create any child controls they contain in preparation for posting back or rendering.
	/// </summary>
	protected override int CreateChildControls(System.Collections.IEnumerable dataSource, bool dataBinding)
	{
	 int pos = 0;

	 if (dataBinding)
	 {
		//Instantiate the Header template (if exists)
		if (m_headerTemplate != null)
		{
			Control headerItem = new Control();
			m_headerTemplate.InstantiateIn(headerItem);
			Controls.Add(headerItem);
		}
		if (dataSource != null)
		{
			foreach (object o in dataSource)
			{
					<%=entityName%> entity = o as <%=entityName%>;
					<%=entityItem%> container = new <%=entityItem%>(entity);

					if (m_itemTemplate != null &amp;amp;&amp;amp; (pos % 2) == 0)
					{
						m_itemTemplate.InstantiateIn(container);

						if (m_seperatorTemplate != null)
						{
							m_seperatorTemplate.InstantiateIn(container);
						}
					}
					else
					{
						if (m_altenateItemTemplate != null)
						{
							m_altenateItemTemplate.InstantiateIn(container);

							if (m_seperatorTemplate != null)
							{
								m_seperatorTemplate.InstantiateIn(container);
							}

						}
						else if (m_itemTemplate != null)
						{
							m_itemTemplate.InstantiateIn(container);

							if (m_seperatorTemplate != null)
							{
								m_seperatorTemplate.InstantiateIn(container);
							}
						}
						else
						{
							// no template !!!
						}
					}
					Controls.Add(container);

					container.DataBind();

					pos++;
			}
		}
		//Instantiate the Footer template (if exists)
		if (m_footerTemplate != null)
		{
			Control footerItem = new Control();
			m_footerTemplate.InstantiateIn(footerItem);
			Controls.Add(footerItem);
		}

	}

		return pos;
	}

I want my .ForEach(System.Action)!

Posted by Monty on October 14th, 2008

Well I was adding things to a dictionary today (Because im lazy, I have to store 2 values, and I really cant be bothered with creating a class just for that), and I wanted to run a ForEach(System.Action<T>) on it, because I like doing that on System.Collections.Generic.List<t> – it works well, so why change what you know?

But, it turns out Dictionary<TKey, TValue> dosent have a .ForEach. It implements IEnumerable, but it dosent have support for the .ForEach, which is rather strange, since they both do the same thing, but it dosent have the Action<T> method. So I did some digging, and found that .ForEach is a method that belongs to List<T>, and its pretty much the only way to do it (There is a System.Array.Foreach(T[] array, Action<T>) method, but that dosent work with a dictionary.

What I see happening is me extending Dictionary<TKey, TValue> to add a .ForEach (And the other functions that are missing from it, in my opinion at least), because I think that since it implements IEnumerable<T>, it should support .ForEach.

Pet Project – Personal ANPR

Posted by Monty on September 16th, 2008

Well iv got a pet project, its creaing my own Automatic Numberplate Recognition System. Why? Because I think it will be very technically challenging to do it in the .net framework.

This is what I have sofar, from an image like this:

it picks up the following:

Not bad, if i say so myself. It needs hell of alot of work though.

MS Build – “Microsoft.WebApplication.targets” was not found.

Posted by Monty on July 22nd, 2008

This is a stupid error, an oversight by Microsoft. As far as I can tell, you can ONLY install the Web Application pack for vs2005 if you have VS installed – you cant install it on a build server, which is nice and “fun”.

A solution is to just create the directory structure it asks for -

C:\Program Files\MSBuild\Microsoft\VisualStudio\v8.0\WebApplications\

And copy over the files from your own copy. I don’t know why Microsoft did it this way, but its criminally retarded.

Edit – You can now download the file from here.

Consider if you actually need a variable…

Posted by Monty on June 16th, 2008

Take this scenario, you need to call a function, so you do the following:

I basically needed to call GetCustomAttribute(true) (if you know a better way to check custom attributes, please let me know!). But then I had an epiphany. Do I really need the trace and frame objects, or can I just do the following:

Which does exactly the same thing, but is shorter, and is easier to read and follow!

I love simplicitiy.

Resharper 4.0 is great

Posted by Monty on June 3rd, 2008

Im gunna do a full post about this later, but for the time being, its time I declared to the world that I love Resharper 4.0 and im going to marry it.

A reason for this:

WindowClipping (2)

WindowClipping (3)

WindowClipping (4)

Simplicity! Beauty! And it works!


Copyright © 2007-2010 Muntedhar Alhakim. All rights reserved.