If you’ve done any amount of web forms development, you certainly couldn’t live without controls like the Repeater or ListView (although some might argue that the ListView control replaces the Repeater control). I had an interesting feature I was developing that ended up with a Repeater control containing a nested user control of sorts.

I had a couple goals in mind. The first was to be able to render some of the bound data straight to the Repeater control, the more typical usage pattern. The second was to be able to pass along some of the bound data to a nested user control within the Repeater. I’ve simplified the concept below:

<asp:Repeater ID="ProfileRepeater" runat="server" OnItemDataBound="ProfileRepeater_ItemDataBound">
	<ItemTemplate>
		<div>
			<%# Eval("Name") %>'s Profile
			<CBControls:Profile ID="UserProfile" runat="server" />
		</div>
	</ItemTemplate>
</asp:Repeater>

With the UI markup clarified above, the databinding was a fairly typical setup leveraging an anonymous type as follows:

protected void Page_Load(object sender, EventArgs e)
{
		//Retrieving all profiles from our hypothetical data provider
		IEnumerable<Profile> profileData = Profile.GetAll();

		//Binding the profiles to our UserProfile control
		UserProfile.DataSource = profileData
			.Select(data => new {
				Name = data.firstName + " " + data.lastName,
				Age = data.age,
				Location = data.location,
				Hometown = data.hometown
			});

		UserProfile.DataBind();
}

So the idea was to bind, say the “Name” to the Repeater, but I wanted the rest of the data (“Age”, “Location” and “Hometown”) to be consumed by the nested user control. The key to accomplishing this is via the OnItemDataBound event, as specified above in the markup. The implementation for this is as follows:

protected void ProfileRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
	if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
	{
		Profile ctrl = e.Item.FindControl("UserProfile") as Profile;

		if (ctrl != null)
		{
			//.NET 3.5 Solution
			ctrl.Age = DataBinder.Eval(e.Item.DataItem, "Age");
			ctrl.Location = DataBinder.Eval(e.Item.DataItem, "Location");
			ctrl.Hometown = DataBinder.Eval(e.Item.DataItem, "Hometown");

			//.NET 4.0 Solution using the new "dynamic" keyword to assist with anonymous type passing
			dynamic currentProfileData = e.Item.DataItem as dynamic;
			ctrl.Age = currentProfileData.Age;
			ctrl.Location = currentProfileData.Location;
			ctrl.Hometown = currentProfileData.Hometown;
		}
	}
}

You’ll notice I have provided both the .NET 3.5 and .NET 4.0 solutions for how one would go about this. In my particular case, the project is leveraging .NET 3.5, but if this were .NET 4.0, things could be accomplished slightly more elegantly using the “dynamic” keyword.

Regardless of which framework you’re using, as the method depicts, it is here where we are passing along the data to the nested user control by assigning it to the controls exposed properties. For those of you who prefer to strongly type everything, you’d simply replace the “dynamic” keyword with your own type (the same type that you would project your databinding to in Page_Load) and you’d be good to go!

One of the popular trends in many companies these days is the implementation of dashboard reporting packages (such as Business Objects or Dundas) over the top of company data in an effort to make more informed business decisions.  While many companies prefer to purchase retail packages for this purpose, there are other scenarios where it makes a lot of sense to roll your own.  Having a solid grasp of a handful of technologies can make this endeavor not only painless, but actually pretty darn fun!  The following is a sample preview of the lab:

One of the first things I noticed was the presence of a Chart control if you looked in the toolbox in VS 2010.  The only caveat here is that I didn’t want to use this control as it was intended, as I prefer to use MVC 2 over web forms.  It turns out you can programmatically leverage the Chart control class in order to make use of its full capabilities without the need to co-mingle web forms with MVC 2 (no thanks).  There are a few things in the following code that are specific to my particular implementation in the lab, but most of the code is fairly general.  The main area I stripped out was the points for the given series that you’ll need to add yourself, depending on your data source and persistence choices.

public FileResult GetChart(SeriesChartType cType, string dimension, bool legend)
{
	//Chart initialization
	var chart = new Chart();
	chart.RenderType = RenderType.ImageTag;
	chart.Titles.Add(cType.ToString());
	chart.Width = 200;
	chart.Height = 200;
	chart.ChartAreas.Add(new ChartArea
	{
		Name = "chartArea1",
		Area3DStyle = new ChartArea3DStyle
		{
			Enable3D = dimension == "3D" ? true : false,
			LightStyle = LightStyle.Realistic,
		},
	});

	//Plotting series data points
	chart.Series.Add(new Series
	{
		Name = "series1",
		ChartType = cType,
		ChartArea = "chartArea1",
	});

	//Managing the chart legend
	if (legend)
	{
		chart.Legends.Add(new Legend
		{
			Docking = Docking.Bottom,
			Alignment = StringAlignment.Center,
			Enabled = true,
			IsDockedInsideChartArea = false,
			Title = "Legend",
			LegendItemOrder = LegendItemOrder.Auto,
		});
	}

	//TODO: Add series points here in the form of "chart.Series["series1"].Points.AddXY(..)"

	//Saving the chart results into a MemoryStream
	var iStream = new MemoryStream();
	chart.SaveImage(iStream, ChartImageFormat.Png);
	iStream.Seek(0, SeekOrigin.Begin);

	//Returning the binary stream data in PNG format
	return new FileStreamResult(iStream, "image/png")
	{
		FileDownloadName = "Chart.png",
	};
}

For my specific lab implementation I also needed a couple additional action methods I coined “UpdateChartData” and “ClearChartData” that are silently called via jQuery through AJAX, but the implementation for them isn’t all that important as is keeping the big picture in mind, each time you trigger an event with the “A”, “B”, and “C” buttons, that event triggers a call to “UpdateChartData” which increases the tally of data points for the button pressed.  If you ever push the “Clear Data” button, that event is silently bound to the “ClearChartData” action method and merely clears the data being persisted.

You may be asking yourself, why 35 charts and not lucky number 7 perhaps?  Simple, I literally iterated through all of the enumerations that the .NET 4 framework offers for charting so that I could use my lab as a kind of “chart browser” if you will for exploring all possible charts.

The jQuery was somewhat lengthy and can be viewed in its entirety in the source for the lab, but I’ll also show it here as there’s a couple nifty little gems sprinkled throughout:

    <script type="text/javascript">
        $(function () {
            $("#btnA").click(function () {
                SendPost("A");
            });

            $("#btnB").click(function () {
                SendPost("B");
            });

            $("#btnC").click(function () {
                SendPost("C");
            });

            $("#btnClear").click(function () {
                SendPostClear();
            });

            $("input:radio[name=dimension]").click(function () {
                RefreshCharts();
            });

            $("input:radio[name=legend]").click(function () {
                RefreshCharts();
            });

            RefreshCharts();
        })

        function SendPost(input) {
            $.ajax({
                type: "POST",
                url: '/Lab/UpdateChartData',
                async: true,
                cache: false,
                data: { input: input },
                success: function (data) {
                    RefreshCharts();
                }
            });
        }

        function SendPostClear() {
            $.ajax({
                type: "POST",
                url: '/Lab/ClearChartData',
                async: true,
                cache: false,
                success: function (data) {
                    RefreshCharts();
                }
            });
        }

        function RefreshCharts() {
            $(".dynamicChart").each(function () {
                enumId = $(this).attr("id");
                $(this)
                    .attr("src", "/Lab/GetChart/?uniqueID="
                        + GetUniqueID()
                        + "&cType="
                        + enumId.substring(3, 100)
                        + "&dimension="
                        + $("input:radio[name=dimension]:checked").val()
                        + "&legend="
                        + $("input:radio[name=legend]:checked").val())
                    .attr("style", "border: 1px #CCCCCC solid;");
            });
        }

        function GetUniqueID() {
            var newDate = new Date;
            return newDate.getTime();
        }
    </script>

One of the gems is the RefreshCharts function.  It grabs all of the image skeletons initially set up for each chart type, extracts the id attribute, chops off the first 3 letters and passes the actual enum along with the rest of the crafted string to the img src attribute, effectively triggering a GET request to our GetChart method.  This is pretty cool since it makes it possible to have everything be managed by a single body of code with no duplication for each chart type.  You might also be wondering what the purpose is behind calling GetUniqueID.  Simply put, this just returns a millisecond representation of time so that we can avoid any sort of browser caching issue since browsers will think it’s a new URL per request for each chart.

If you have any questions about the above, feel free to leave a comment.  Happy charting!