Tuesday, August 29, 2006

Atlas HoverMenuExtender example

The Atlas HoverMenuExtender is one of my favourite controllers in the Atlas toolkit. I've often thought about having all those minor details off the main screen, but still have them easily and quickly accessible. I see this control as a nice easy way to do this, so I'll show you how I'd do that.

What is it?

The Atlas HoverMenuExtender gives you a way to easily add a panel with extra content to a control, without clutteruing up the screen. You can bind all the data in your grid, while at the same time binding your hover menu panel, therefore keeping all you code in one simple place but adding nice functionality.

Pros?
  • Clean up your interface by only showing key data, and showing extra data on hover
  • Have a fast way to show master/detail data
  • Hide all your extra command buttons in a GridView

Cons?

  • For a first time user of your site, it may not be that obvious that extra data is available on mouse over
  • It may also be annoying that menus keep popping up whenever scrolling past a grid
  • Must set the visibility to hidden in the stylesheet to make sure the panel doesn't show quickly when the page is loading
  • As a note I had a slight hitch when trying this extender in a real situation, in that nothing showed. Funnily enough it worked in Firefox though, and it turned out that an "overflow:auto" (ie HTML scroll bar) in another control on that form caused the issue
  • PopDelay says how long to leave the popup there, whereas I would have though it would indicate how long to wait before showing it.

Tips

I feel there are a couple of tricks to the trade here, and some of these apply to other Atlas extenders also:
  • In my example, having width="100%" on the GridRowPanel (panel shown in grid before popup) means the popup will appear anywhere on the grid, otherwise it will only appear when hovering over the actual content. Another way to fix this is have a background color. Also this works as I would have expected in Firefox, just not IE.
  • The popup window must be hidden by default, otherwise you will notice the control breifly while the page loads. Atlas will make it visible again when it needs to. Do this with Visibility:hidden in the stylesheet or add style="display:none"
  • The HoveMenuExtender MUST be placed in the ItemTemplate/EditTemplate etc for a GridView. This is because the target control is internal to that template, and therefore isn't visible to controls outside the grid.
  • Certainly on a grid PopDelay should be short to avoid ugly or unreadable popups for other rows.


Example
In this example, I'd like to show a few extra fields in a GridView when hovering over a row with the mouse.
  1. Add an Atlas ScriptManager to the form
  2. Setup a GridView with an ItemTemplate with many columns
  3. Add the databinding code how you wish to your data.
  4. In the ItemTemplate have one panel for the columns you want to show and one for the columns you want to have as the hover panel
  5. Make sure the hover panel has Visibility:hidden in the style or style="display:none" in the panel tag
  6. Add a HoverMenuExtender inside the ItemTemplate
  7. Set the TargetControlID to the panel you want to permanently display on the grid.
  8. Set the PopupControlID to the panel you want to show when the mouse hovers over the grid
  9. Finally set a HoverCssClass for how you want the main grid row to look when hovered over
  10. PopupPosition dictates on which edge of the TargetControlID you want the popup to appear
  11. OffsetX, OffsetY say how far down and right to place the popup from PopupPosition.
  12. PopDelay means how long the popup will show once the mouse leaves the control. Set this to a low amount on grids.

Here is the code:

<%@ Page Language="C#" %>
<%@ Register Assembly="AtlasControlToolkit" Namespace="AtlasControlToolkit" TagPrefix="cc1" %>
<%@ Import Namespace="System.Collections.Generic" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

public class Mp3Class
{
private int _Mp3Number;
private string _Artist;
private string _SongTitle;
private decimal _Rating;

public int Mp3Number { get { return _Mp3Number; } set { _Mp3Number = value; } }
public string Artist { get { return _Artist; } set { _Artist = value; } }
public string SongTitle { get { return _SongTitle; } set { _SongTitle = value; } }
public decimal Rating { get { return _Rating; } set { _Rating = value; } }

public Mp3Class(int Mp3Number, string Artist, string SongTitle, decimal Rating)
{
this.Mp3Number = Mp3Number;
this.Artist = Artist;
this.SongTitle = SongTitle;
this.Rating = Rating;
}
}

protected void Page_Load(object sender, EventArgs e)
{
List<Mp3Class> Mp3List = new List<Mp3Class>();
Mp3List.Add(new Mp3Class(1, "Bernard Fanning", "Wish You Well", 8));
Mp3List.Add(new Mp3Class(2, "Ben Lee", "Catch My Disease", 7));
Mp3List.Add(new Mp3Class(3, "Gorillaz", "Feel Good Inc.", 9));
Mp3List.Add(new Mp3Class(4, "Foo Fighters", "Best Of You", 6));
Mp3List.Add(new Mp3Class(5, "Gorillaz", "Dare", 9));
TopFiveList.DataSource = Mp3List;
TopFiveList.DataBind();
}
</script>

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Atlas HoverMenuExtender</title>
<style type="text/css">
.popupMenu {background-color:Silver;position:absolute;visibility:hidden;border-width:1px;border-style:solid;border-color:Black;}
.popupHover {background-color:Gray;
</style>
</head>
<body>
<atlas:ScriptManager ID="scriptmgr" runat="server"></atlas:ScriptManager>
<form id="form1" runat="server">
<h2>Top 5 Mp3's</h2>
<div>
<asp:GridView ID="TopFiveList" ShowHeader="false" GridLines="Both" Width="200px" AutoGenerateColumns="False" runat="server">
<Columns>
<asp:BoundField Visible="false" DataField="Mp3Number" />
<asp:TemplateField>
<ItemTemplate>
<asp:Panel ID="HoverPnl" CssClass="popupMenu" Width="300px" runat="server" style="display:none">
<table>
<tr>
<td>
<b>Artist</b></td>
<td>
<asp:Label ID="ArtistLbl" Text='<%# Eval("Artist") %>' runat="server"></asp:Label></td>
</tr>
<tr>
<td>
<b>Song Title</b></td>
<td>
<asp:Label ID="Label1" Text='<%# Eval("SongTitle") %>' runat="server"></asp:Label></td>
</tr>
<tr>
<td>
<b>Song Rating</b></td>
<td>
<asp:Label ID="Label2" Text='<%# Eval("Rating") %>' runat="server"></asp:Label></td>
</tr>
</table>
</asp:Panel>
<asp:Panel ID="GridRowPnl" Width="100%" runat="server">
<asp:Label ID="Label3" Text='<%# Eval("SongTitle") %>' runat="server"></asp:Label>
</asp:Panel>
<cc1:HoverMenuExtender ID="HoverMenuExtender1" runat="server">
<cc1:HoverMenuProperties PopupPosition="right" HoverCssClass="popupHover" PopupControlID="HoverPnl"
TargetControlID="GridRowPnl" PopDelay="50" />
</cc1:HoverMenuExtender>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
</form>
</body>
</html>


kick it on DotNetKicks.com

Tuesday, August 22, 2006

Atlas Extender with code behind

So my first venture into Atlas code was to convert a fairly simple winforms app into a webform. I wouldn't have dreamt of doing this without Atlas or AJAX, because although it's dealing with data (which .net does so well), there is also a lot of drag and drop, resizing panel etc etc. The only other problem is that it's also building the page dynamically in the winforms app, which leaves me wondering how the extenders can be used if they are usually created in the aspx source. Fortunately there is a way.

What is it?

An extender is the same as my previous blog, but in this case it's linking the controls to the extender using server side or code behind code. Without this ability, we'd be stuck with Atlas effects on only the controls you can design.

How does it help me?

It will only help if you need to add controls dynamically. Where you can I'd still suggest to put the properties on the form itself like previously explained.

Pros?

  • Gives you the ability to add controls dynamically and still give them Atlas behaviors

Cons?

  • Extender properties can't be added after the page init procedures. Eg a button click happens after a page init, therefore you can't add extender properties in a button click.
  • You must add the dynamic controls to the form before finalising your extender properties. So if the code is adding a lot of controls to a panel, you must wait until the panel is added to the form before adding the extender properties.
  • Potentially adds more difficultly to debugging.

Example

Another simple example here with an Atlas DragPanelExtender. No controls on the aspx form, and one control added dynamically to the DragPanelExtender.

  1. Add an atlas ScriptManager to a webform.
  2. Drag an atlas DragPanelExtender onto the form.
  3. Double click on the form to create a Page_Load method in your code behind.
  4. In the code behind dynamically add a panel, another panel within that panel to be the drag panel, and another control to be the content inside the main panel.
  5. Add these to the form.
  6. Now create a DragPanelProperties object and set the TargetControlID to the main panel and the DragHandleID to the header panel which is to be the draggable control.
  7. Link this to the control to the extender by adding the object to the TargetProperties collection.
  8. All done, the dynamic control will now appear with the Atlas effects also.

Full Code:




<%@ Page Language="C#" %>

<%@ Register Assembly="AtlasControlToolkit" Namespace="AtlasControlToolkit" TagPrefix="cc1" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
BuildPageDynamically();
}
}

private void BuildPageDynamically()
{
// One of 3 main panels.
Panel p = new Panel();
p.Height = 200;
p.Width = 200;
p.ID = "Panel1";
p.BorderWidth = 1;
p.BackColor = System.Drawing.Color.PaleVioletRed;

// Add a header panel to drag by.
Panel HeaderPanel = new Panel();
HeaderPanel.Height = 20;
HeaderPanel.Width = 200;
HeaderPanel.ID = "HeaderPanel1";
HeaderPanel.BorderWidth = 1;
HeaderPanel.BackColor = System.Drawing.Color.PapayaWhip;
p.Controls.Add(HeaderPanel);

// Add a label in the main panel.
Label l = new Label();
l.Text = "Drag me";
l.Width = 200;
p.Controls.Add(l);

// Add the main panel onto the main form
this.Controls.Add(p);

// Create a new properties for the extender.
DragPanelProperties dpp = new DragPanelProperties();
dpp.TargetControlID = p.ID;
dpp.DragHandleID = HeaderPanel.ID;

// Add the properties to the extender
DragPanelExtender1.TargetProperties.Add(dpp);

}
</script>

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Atlas Extender Code Behind</title>
<atlas:ScriptManager ID="scriptmgr" runat= "server" />
</head>
<body>
<form id="form1" runat="server">
<cc1:DragPanelExtender ID="DragPanelExtender1" runat="server">
</cc1:DragPanelExtender>
</form>
</body>
</html>

kick it on DotNetKicks.com

Monday, August 21, 2006

Understanding Atlas Extenders

I'm not here to offer a brilliant new view on what an Extender is, but I feel my lack of higher education sometimes leaves me scratching my heads on Microsoft’s explanation of their good work, so I’m here to give an easy example of what an Atlas extender does for you.

What is it?
.net has a great feature in extensibility. What is this? It means that if you write a new effect you can implement it on controls that don't have that functionality. The best example in winforms is the ToolTip. Before you drop a ToolTip on a form, you have no way of having hints, but once you've dropped one on a form, all your controls suddenly have a "ToolTip on toolTip1" property where you can add a hint.

An Atlas extender does a similar thing for web controls. It adds properties onto your web controls, to allow special AJAX or javascript effects without needing inheritance or anything complex to work.

How does it help me?
Generally Atlas extenders are at their most useful when there is a nice javascript feature you have, but you want to attach it to your asp.net web controls. Rather than inheriting controls to add javascript niceness, you simply write an extender and use it on what controls you want to.

Pros?

  • There is nothing stopping you writing your own, but Microsoft has already gathered over 20 different extenders written by various authors. This is available for download in the Atlas toolkit http://atlas.asp.net/atlastoolkit/.
    This alone makes Atlas a compelling argument. Imagine that every decent extender that gets written gets added to the Atlas toolkit. By this time next year we could have 100 controls, which any user can access by simply downloading the toolkit.
  • After writing the extender, you can get javascript features in your web controls without writing a line of javascript code. This is nice as feature rich controls come without writing complex javascript code in your web form. The less code on the main page the better.
  • Another nice feature is you can see which Atlas extenders have been added to your web control in the Properties section. Compare this with trying to dig through javascript to see which control a certain web control that function effects and you’ll realise the Atlas extender way is much neater.
  • You can add extender properties in server side code (code behind). Very nice.

Cons?

  • I’m not an expert here, but it seems to me that as the toolkit grows, so will the size of the included toolkit dll, and therefore slow down initial page loads at a new site. This of course isn’t a downside of extenders, but the toolkit itself.
  • Also the extenders don’t work on html controls like a div (from what I’ve seen), so you’re stuck using the asp version of that control, which can make it harder to get extra javascript functionality sometimes.
  • From what I’ve seen you can’t add the extender properties to a control in the design view, but once they’re added you can see them there. (at least this isn't working on my Web Developer Express)
  • On the other hand you can't see the extender properties in the source view.

Example
I’ll give a simple example here, because I’ll probably go through a lot of these controls in more detail later on. For now I’ll show the simplest example. It will extend an asp:Button to include a confirmation dialog using the ConfirmButtonExtender:

  1. Add an Atlas ScriptManager to the form.
  2. Drag a ConfirmButtonExtender onto a web form.
  3. Dragging this adds a simple extender tag. All extender tags have a list of property tags within them to attach an extender to a control and give it other properties.
  4. Drag an asp:Button onto the web form. Call it “AtlasBtn”.
  5. Goto the Source view and find the ConfirmButtonExtender.
  6. Start adding a new tag in the middle of that tag by pressing “<”. IntelliSense should kick in and show cc1:ConfirmButtonProperties
  7. Add properties in there for ConfirmText (like "Are you really sure?") and TargetControlID="AtlasBtn".

That’s all there is to it. Now when the user clicks on that button, the server side code on AtlasBtn will only execute once the user confirms the dialog, otherwise nothing will happen. Note also that when clicking on AtlasBtn in the Design view now, the properties show the Atlas Extender

Full code:




<%@ Page Language="C#" %>

<%@ Register Assembly="AtlasControlToolkit" Namespace="AtlasControlToolkit" TagPrefix="cc1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

protected void AtlasBtn_Click(object sender, EventArgs e)
{
Response.Write("Added this text through server side code now.");
}
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Atlas Extender example</title>
</head>
<body>
<atlas:ScriptManager ID="scriptmgr" runat="server" />
<form id="form1" runat="server">
<div>
<asp:Button ID="AtlasBtn" runat="server" Text="Click to add" OnClick="AtlasBtn_Click" />
</div>
</form>
<cc1:ConfirmButtonExtender ID="ConfirmButtonExtender1" runat="server">
<cc1:ConfirmButtonProperties ConfirmText="Are you really sure?" TargetControlID="AtlasBtn" />
</cc1:ConfirmButtonExtender>
</body>
</html>

kick it on DotNetKicks.com

Tuesday, August 15, 2006

Why I'm here.

My reasons?

What sort of world do we live in, when someone like me is starting a blog? It's still a hard question to answer, but it's best answered by explaining why I shouldn't start a blog. I barely passed English in high school, so my writing skills are average. I never studied at uni, so my programming skills are mostly self taught. I'm usually one of the last to know of cool technologies, and rarely dig deep enough to get the full picture of any one technology. And I certainly don't have inside knowledge or know people who work for Microsoft.

My background

OK, maybe I need to go back a little further. I did do some studies, acheiving a diploma in computer programming in Perth, Western Australia, where I grew up. It was a career change (or start), based mostly on my love for computers and self taught games programming in C++. I learned mainly from internet tutorials and a couple of books, about the time Doom was the PC benchmark game. I didn't keep any of that code, but I can safely say my programming sucked. It got slightly better by the time I was graduated, and my background was enough to assure high grades.

My first workplace was a small custom software house, programming Delphi applications. It was an excellent hands on job, covering programming, customer support, quoting, and database design. I was taught a lot, but I do feel like I'd never learned to program the best way. I didn't spend my free time learning, so my development was slow.

2 and 1/2 years later it was time to move to Sydney for work reasons and for Kirsty (now my wife and mother of my son Luke, 1, with another due later this year). Another couple of years was spent working for retailer Dick Smith Electronics again mainly in Delphi and interbase, mainly getting out of bad programming habits thanks to the help of an excellent programming team. After a while I finally found my own urges to learn more, and .net was the clean break I needed. I've still got my job with Dickies, and my last 3 years have been split between Delphi and Visual Studio.net apps. My works been great helping me to work more on the project side of things, but I've decided to keep pushing my programming knowledge further also.

So . . . my reasons?

Oh yeah, I knew there was a point. I've read plenty of blogs over the last couple of years, but there's no doubt, that subscribing to a few blogs recently filled me in a lot more on blogs. It's not just about experts giving up their knowledge for free, it's also about getting good information more widely distributed, because even if it's not your own work, I still want to know about it. It's also about having a central place to find out about a single technology... like Atlas.

Atlas is not even released yet, but already it's blown me away. My web programming skills are almost non-existant, mainly because programming for the web was painful compared with Delphi apps. .net changed that somewhat, .net 2.0 somewhat more, but it was AJAX that really got me interested. But then again, there were several small implementations for .net AJAX assemblies and support/documentation/tutorials was very low, so I didn't jump in head first. So I was thrilled to see Microsoft attempting an AJAX implementation, which is of course Atlas. Once you've put your first UpdatePanel on a form you're hooked. And even though documentation/support for Atlas is low at the moment, and there are problems with it (come on it's a beta), I feel like it's worth the effort to work it out.

And while I'm here I'll also put up interesting notes from .net Winforms apps, and keep an eye out for .net 3.0, which is shaping up to be a big step up especially looking at WPF and WPF/E. And given the current rate of development at Microsoft there will be plenty of things worth blogging about in the next year or so.

If you've read this far you've done well, thanks for reading. I'll be looking to start with some Atlas basics over the next few days, and hopefully not entirely embarrass myself or mislead people.

Yay, my first blog.