Google Reader’s New Clothes

First post in a while but I’m hoping to find time over the next few weeks to write about some of the things I’ve been up to lately including working with Silverlight, MVC and some good ‘old-fashioned’ .NET 3.5. Next post will be on my experiences with the possibilities (and the steep learning curve) given by the Microsoft Oslo platform.

Since it’s a Friday I thought I would put up a quick post inspired by the new look Google Reader released today with details on the official blog. I thought I would go my own way with the Helvetireader theme (using GreaseMonkey to support the scipt) for now and I like the streamlined, clean approach…

Helvetireader

However, it’s clear that some real estate was being wasted so I changed tack and chose to use the standalone Helvetireader CSS with Stylish to allow me to tweak it slightly:

  1. Changed the max width so that there is no whitespace when reading with the subscriptions panel open

    .entry .entry-body, .entry .entry-title {
    max-width:1000px;
    }
  2. Removed the post entry options background images as this was overlapped by the options themselves when the Preview function was in place

This gave a good result..

Helvetireader-with-changes

The tweaked CSS can be found here.

The good thing about using either a GreaseMonkey script or a Stylish theme is that I can preserve the great functions offered by Better GReader, an essential Firefox extension which I have been using for some time. It looks like the Preview post function is not working in the latest version (v0.4). I reinstated this by installing the GreaseMonkey script provided by Julien Carosi at userscripts.org (making the changes given in a comment on the script).

This function is great as it enables you to stay within Google Reader while viewing the blog as it appears in its original form, either to view/post comments or read the entire post if the blogger has only provided a snippet/teaser via RSS.

Post Snippet Post Preview

To be honest, this practice annoys me and others. It would be understandble if this was the only way to provide marketing content but blogs such as Los Techies have proved otherwise. Luckily, with technical/development blogs, ‘after the jump’ syndrome is relatively rare perhaps due to the tech bloggers being keen consumers of syndicated content.

Image Gallery and AdRotator

First post, and some of my first real C# coding!

Following a couple of examples in Asp.Net 3.5 Unleashed, I created a form that uploaded images to an image gallery which was displayed on the same page. To improve on this, I added the option to select the type of image to be added.

A 'Gallery' image would be saved to /Assets/Images and displayed in the image gallery. An 'Advert' image would be saved to another folder and the accompanying details (ImageUrl, NavigateUrl and AltText) written to an xml file.

using
System;
using
System.Xml;
using
System.IO;

partial class WebUserControl : System.Web.UI.UserControl
{
public void Page_Load(Object sender, EventArgs e)
{
btnImage.Click += (Button_Click);
}
protected bool imageIsAd;
protected void AdRadio_CheckedChanged(object sender, EventArgs e)
{
imageIsAd =
true;
}
protected void GalleryRadio_CheckedChanged(object sender, EventArgs e)
{
imageIsAd =
false;
}

public void Button_Click(object sender, EventArgs e)
{
if (!imageUpload.HasFile) return;
if (!imageIsAd)
{

var filePath = "~/Assets/Images/" + imageUpload.FileName;
imageUpload.SaveAs(MapPath(filePath));
}

var adPath = "~/Assets/Ads/" + imageUpload.FileName;
imageUpload.SaveAs(MapPath(adPath));
WriteXml();
ImageLink.Text =
String.Empty;
AltText.Text =
String.Empty;
}

void Page_PreRender()
{
var imgFolder = MapPath("~/Assets/Images/");
var dir = new DirectoryInfo(imgFolder);
dlstImages.DataSource = dir.GetFiles();
dlstImages.DataBind();
}

Then I created the WriteXml method to perform two functions:
  1. If the xml file (Adlist.xml) does not exist, create the xml with the details of the image submitted via the form.
  2. If the xml file does exist, insert the details of the submitted image maintaining the correct nesting and formatting.
The example in the book created the file by loading in the raw xml content. I thought that it was better to create the file programmatically. One gotcha I came across was having to use the absolute path for the xml file loaded by XmlTextWriter and XmlDocument.Load.

protected void WriteXml()
{
if (!imageIsAd) return;

System.Drawing.
Image UppedImage = System.Drawing.Image.FromStream(imageUpload.PostedFile.InputStream);
float UploadedImageWidth = UppedImage.PhysicalDimension.Width;
float UploadedImageHeight = UppedImage.PhysicalDimension.Height;
var imagePath = "~/Assets/Ads/" + imageUpload.FileName;
var xmlFile = @"Absolute Path to AdList.xml";
var xmlFileInfo = new FileInfo(xmlFile);
if (!xmlFileInfo.Exists)
{
var writer = new XmlTextWriter(xmlFile, null);
writer.WriteStartDocument();
writer.WriteRaw(
"\n");
writer.WriteStartElement(
"Advertisements");
writer.WriteRaw(
"\n");
writer.WriteStartElement(
"Ad");
writer.WriteRaw(
"\n");
writer.WriteStartElement(
"", "ImageUrl", "");
writer.WriteString(imagePath);
writer.WriteEndElement();
writer.WriteRaw(
"\n");
writer.WriteStartElement(
"", "Width", "");
writer.WriteString(UploadedImageWidth.ToString());
writer.WriteEndElement();
writer.WriteRaw(
"\n");
writer.WriteStartElement(
"", "Height", "");
writer.WriteString(UploadedImageHeight.ToString());
writer.WriteEndElement();
writer.WriteRaw(
"\n");
writer.WriteStartElement(
"", "NavigateUrl", "");
writer.WriteString(ImageLink.Text);
writer.WriteEndElement();
writer.WriteRaw(
"\n");
writer.WriteStartElement(
"", "AlternateText", "");
writer.WriteString(AltText.Text);
writer.WriteEndElement();
writer.WriteRaw(
"\n");
writer.WriteEndElement();
writer.WriteRaw(
"\n");
writer.WriteEndElement();
writer.WriteRaw(
"\n");
writer.WriteEndDocument();
writer.Close();
}

else
{
var xdoc = new XmlDocument();
xdoc.Load(xmlFile);
var adverts = xdoc.SelectSingleNode("Advertisements");
XmlElement ad = xdoc.CreateElement("Ad");
XmlElement img = xdoc.CreateElement("ImageUrl");
img.InnerText = imagePath;
XmlElement width = xdoc.CreateElement("Width");
width.InnerText = UploadedImageWidth.ToString();
XmlElement height = xdoc.CreateElement("Height");
height.InnerText = UploadedImageHeight.ToString();
XmlElement navUrl = xdoc.CreateElement("NavigateUrl");
navUrl.InnerText = ImageLink.Text;
XmlElement xaltText = xdoc.CreateElement("AlternateText");
xaltText.InnerText = AltText.Text;
adverts.AppendChild(ad);
ad.AppendChild(img);
ad.AppendChild(width);
ad.AppendChild(height);
ad.AppendChild(navUrl);
ad.AppendChild(xaltText);
xdoc.Save(xmlFile);
}
}
}

Next time I would think about breaking the WriteXml method out into a class and storing image details in an database rather than in an xml file on the file system.