Making Your LinkButton look (and work) like an ImageButton
Hey there,
I don’t know if you’ve noticed, but style sheets tend to handle an <input type=image/> a lot differently than an <img/> tag. And that becomes a problem in .NET if you’ve built a webform that depends on a link to be an image.
The LinkButton control doesn’t support an ImageUrl. It renders like you’d expect, with an <a/> tag surrounding some text, and the Href on that <a/> tag pointed at a __doPostBack function of some type. But there’s no way to tell it to use an image as the text, without setting the text manually through the designer or maybe with some code.
On the other hand, the ImageButton control only supports images. It renders differently as well, using an <input type=image/> tag as opposed to an <a/> tag. If you’ve styled expecting that <input/> to be an <a/>, you could be in for some time-wasting CSS fun.
In addition, you can’t just easily switch between the two on the page if you want to go from an ImageButton to a LinkButton, because the attributes aren’t consistent regarding the use of images.
My solution to this was to create my own extended LinKButton that supports an ImageUrl. Here’s how I did it.
First, I added an ImageUrl property to my derived LinkButton:
public class MyImageButton : LinkButton
{
private string _imageUrl;
[Editor(“System.Web.UI.Design.ImageUrlEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a”, typeof(UITypeEditor))]
[DefaultValue(“”)]
[UrlProperty]
[Bindable(true)]
public string ImageUrl
{
get { return _imageUrl; }
set { _imageUrl = value; }
}
}
Notice a couple of things: I set the editor and the designer attributes such that my ImageUrl will behave in the Studio the same way that the ImageUrl on an ImageButton would work. This helps to make switching back and forth easier (although with this in place I’d never use an ImageButton again; for me there’s simply no need).
Once I have that, I am going to override OnPreRender:
public class MyImageButton : LinkButton
{
private string _imageUrl;
[Editor(“System.Web.UI.Design.ImageUrlEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a”, typeof(UITypeEditor))]
[DefaultValue(“”)]
[UrlProperty]
[Bindable(true)]
public string ImageUrl
{
get { return _imageUrl; }
set { _imageUrl = value; }
}
protected override void OnPreRender(EventArgs e)
{
if (!string.IsNullOrEmpty(this.ImageUrl))
{
if (this.ImageUrl.Trim().Length > 0)
{
string cssClass = string.Empty;
if (!string.IsNullOrEmpty(CssClass))
{
cssClass = ” class=\”” + CssClass + “\””
}
this.Text = “<img src=\”” + this.ImageUrl + “\” ” + cssClass + “/>”
this.ImageUrl = string.Empty;
}
}
base.OnPreRender(e);
}
In this step, if I have an ImageUrl, I am using code to set the Text property of my LinkButton, and then erasing the ImageUrl so that it will render with an <img/> tag in the text of the <a/>. I’m also taking care to apply the CssClass appropriately to the <img/> tag so that styles will work as expected, the way they would on an ImageButton (assuming the ImageButton was able to output an <img/> instead of an <input/>). With a little more care I could even bring over things like AlternateText if I chose.
With this in place, now I can style consistently between my Text-based and my Image-based buttons without having to worry about inconsistencies in the rendering of the control.
Have fun,
Rob
A generic cloning method
Hey all,
As you know I’m big on Reflection, and big on Generics…now, here’s a method that combines the two for a neat little cloning tool.
Let’s assume we have a base object we use for objects, and let’s call it DataObject. Anything can derive from this object, and in addition, I’m going to add the following method to allow me to “clone” the properties of my current object onto the properties of any other object, provided the Name and Type of the property match.
Notice that I am using the generic t notation for a generic object, and this becomes a generic method.
public class DataObject
{
public t Clone<t>()
{
//reflection based clone
Type tType = typeof(t);
t item = (t) Activator.CreateInstance(tType);
PropertyInfo[] props = tType.GetProperties();
foreach (PropertyInfo prop in props)
{
try
{
prop.SetValue(item, prop.GetValue(this, null), null);
}
catch { }
}
return item;
}
}
Ok, now that that’s done, let’s create two more classes, a Dog, and a Cat.
public class Cat : DataObject
{
private string _name;
public string Name
{
get { return _name;}
set { _name = value;}
}
private string _color;
public string Color
{
get { return _color;}
set { _color= value;}
}
}
public class Dog : DataObject
{
private string _name;
public string Name
{
get { return _name;}
set { _name = value;}
}
private string _color;
public string Color
{
get { return _color;}
set { _color= value;}
}
}
Ok, let’s create a Cat.
Cat cat = new Cat();
cat.Name = “Fluffy”;
cat.Color = “Orange”;
Now that we have that, we can create a Dog from the Cat:
Dog dog = cat.Clone<Dog>();
Once this method is called, the dog will have the exact same properties as the cat…this is useful in particular if you are adjusting properties on objects that are similar enough while in a loop (for example, you are looping on creating email objects that you are placing in a list) and you find yourself in a position where just overriding the properties on the current object won’t work.
Happy cloning!
Rob
Jekyll and Hyde Code Camp Experience
So I went to the Deer In The Headlights Code Camp in Waltham, Mass at the end of March. I’m originally from New England so I thought I would take a long weekend, see my parents and a few friends, then give a talk or two at the Code Camp, stop in to see my twin neice and nephew, and then head home. Coming out of this I’ve decided something for sure at Code Camps in the future: I am never again giving more than one talk at a a code camp.
For starters, the car I rented decided to blow a tire just after all the businesses closed on Saturday afternoon. Now, I’m scheduled to give two talks in succession the next morning at 9 am, two hours away. I considered driving down to Waltham on the spare donut, but I’ve done that in the past with disastrous results. Which leads me to being up all night worrying and finally deciding to borrow my dad’s Impala, drive the two hours to Waltham, give my two talks, drive the two hours back to my parents, get the tire repaired, the drive the two hours back to Boston to spend the night with my sister and the twins before flying home to California the next day.
In addition, I hadn’t given either talk in months and I realized looking at the schedule that while my talks were built around 60 minutes speaking and 15 minutes questions, the schedule indicated I would need to speak for closer to 90 minutes…and now with a flat tire I had little time to prepare and adjust.
In any event, the first talk I gave was on Generics and I decided to scrap my entire powerpoint and just do code samples, and it went fantastic. Even though I was on 4 hours’ sleep it had to be the best talk I ever gave. People afterward were even coming up and telling me it was the best review of Generics they had ever seen. I was very satisfied.
And then I followed it up with the worst talk I had ever given. My talk on Reflection is very dry and hard to do code samples because you either get it or you don’t. You either understand the situations where you would use Reflection or you don’t. Reflection can be a very powerful tool if you can recognize it. In the past I’ve had audiences who had enough people in the crowd who understand that enough dialogue was generated to demonstrate effectively. However, I felt that I was not communicating well enough this time to draw out the group, and I had not had the time I had put into my Generics talk because of my tire issues. I felt like no one really got anything out of the talk, and because of the lack of dialogue, the talk ran well short. Basically a disaster and I owe everyone who saw that talk an apology.
So the moral of the story is, don’t do more than one talk unless you know they are both crisp and ready to go!
I’ve attached links to the Generics code samples and the Reflection demo. Someone asked me to port the Generics code over to VB.NET but 80% of my demo was based around leverage anonymous methods and VB.NET doesn’t support them, so it didn’t make much sense to do the porting.
Also, sorry about the delay in getting these to you…it’s been a hectic month. My wife is due in 8 weeks and my company is about to put its first major project into QA and I’ve just been swamped, but in a good way 🙂
Thanks for your patience!
Rob
