Wednesday, November 08, 2006
Vista is RTM and pricing.
http://windowsvistablog.com/blogs/windowsvista/archive/2006/11/08/windows-vista-releases-to-manufacturing.aspx
While plenty of work has been going on in Microsoft, a lot of discussion has been happening outside discussing the features, version comparisons and pricing of Vista.
My current reasons why I would upgrade to Vista from XP include:
IIS7
Improved Media Centre
Nice built in search
Easier to find and open any programs
Built in .net 3.0, IE7, Media Player 11, DVD movie maker
Excellent backup restore options
Repartioning tool
Use USB key to speed up computer (at $Au27 for 1GB very cheap speed increase)
And why I wouldn't:
Home Premium doesn't have remote desktop or IIS, which means it's a downgrade from XP media centre
Too many annoying popups when doing daily tasks
May still not be stable enough compared to XP
Price, in Australia at least
So what do I mean by price in Australia? Take a quick look at two upgrade options I have and compare US prices to Australian prices:
Home Premium Upgrade
$US in US = $159
$US in Au = $230
Ultimate Upgrade
$US in US = $259
$US in Au = $380
That's RRP, so it's likely big US chains will come out even cheaper (as should a few Australian stores to). But have a look at the gap between Ultimate upgrade prices in Australia and the US. Rediculous!
I'm certainly going to heavily investigate my options of getting a copy in the US, even though I know it will be locked down pretty tight.
That said I'm willing to upgrade and hoping to get Ultimate given the few extra features that I will use.
Monday, November 06, 2006
.net 3.0 official release
Check out all the usual downloads for the official version here:
http://www.netfx3.com/blogs/news_and_announcements/archive/2006/11/06/.NET-Framework-3.0-has-been-released_2100_.aspx
And of course don't forget the Virtual labs to help you get up and running:
http://labs.netfx3.com/
UPDATED:
Here is the whole list of links including the Office 2007 downloads for Visual Studio and AJAX for asp.net:
http://msdn.microsoft.com/vstudio/devsolutions/
And since it's supported on XP and every version of Vista, I'm looking forward to getting stuck into WPF especially over the next few months now.
Thursday, November 02, 2006
Vista retail licensing. Microsoft backs down.
Vista retail licensing has been a well discussed topic over the last few weeks. In short for someone like me it went like this:
As long as I only upgrade my machine hardware once in the years that I want to use Vista as my OS, I'm fine. Once I upgrade a 2nd time though I need to buy a new version of Vista. To me this is scarey, and means I'd really want to make sure the next hardware upgrade would be a good one, as I'm not that happy with outlaying hundreds of dollars after only owning Vista for a couple of years.
BUT NOT ANY MORE!!!!!
Microsoft have officially backed down and will now allow a single user to upgrade their hardware as much as they like. For me that takes the expected usage from 2-3 years, to whenever a better OS worth buying comes out, as I'm more than happy with my core hardware like the case, and will most likely just upgrade components as mine get out of date.
Take a look at the official blog about this:
http://windowsvistablog.com/blogs/windowsvista/archive/2006/11/02/news-revision-to-windows-vista-retail-licensing-terms.aspx
Very good news from Microsoft, thanks for listening to the 5-10% of people who would actually care about this change of licensing.
Monday, September 25, 2006
WPF for beginners: Hello world
Getting started:
- In Visual Studio 2005 goto File -> New -> Project from the main menu
- Select Project Type "NET Framework 3.0"
- Choose "Windows Application (WPF)" (note that XAML Browser Application would be near identical code, except will run in a browser)
- Change the name and location if needed and press OK.
XAML
XAML is the new forms designer technology for WPF. I'm not going to go into detail about XAML, but there are some cool features you'll see in these examples. Firstly, controls have become infinitely more flexible than Winforms. Take for example a Button. Like Winforms you have basic properties like Background and Foreground colors, and can simply put some text in between the tags and have a button. Add a Click event and off you go ... BUT XAML allows you to take that text away and put a Panel in the Button tags. And in that panel, you can put other controls. If you want your button to have 3 images side by side, with text going diagonally across the images, you can. Not only for buttons, most controls allow this feature. The "content" area of a button or other controls only allow one child, but once that child is a panel, you suddenly open up a whole new world.
Another cool feature is the Properties design. Within your Button tag, you can simply put a Background="White" to set the Background property, much like Winforms. But again, you can open this up, but adding a tag after the Button tag, like <Button.Background>. Inside those tags, you suddenly have a lot of freedom again, and can add images, gradients, etc. Other Properties can do other sorts of things too, and in many cases I've found it beneficial adding these tags outside the main tag, as flexibility follows.
Also remember that XAML has inheritence built in nicely. Controls can inherit properties from the parent controls, which is handy for databinding etc. Styles also can inherit from other styles, which makes building a consistant but complicated GUI relatively easy. And again with animations, like scaling a control to be bigger, child object simply scale with it, and even other animations will apply over that new size.
Resources
Very widely used, we can store styles in a Resource section, in this case <Window.Resources>, which would most likely come straight after the root Window tag. In XAML, these resources can be referenced by calling StaticResource and using the x:Key name. So if we have a Style in the Windows.Resources section, we need to give it a key like <Style Key="StandardButtonStyle">. To use this style <Button Style="{StaticResource StandardButtonStyle}">.
Style
A lot of power comes from our style objects. You can take these as far as you want to really. Like CSS stylesheets for HTML we can setup standard looks for our controls, setup styles to target specific control types (ie. all buttons on a form), inherit from other styles and even triggers styles and animations from events and properties of the control. What was formerly not possible, or at least very tricky with lots of code, can now take only a few lines of XAML and effect many controls.
As mentioned earlier a Style must have an x:Key so that other controls can find it using StaticResource. Also mentioned we can inherit from another style using BasedOn="{StaticResource EarlierStyle}". This allows you to build styles from a basic look adding extra functionality as you go up. A style can also target a type of items like this TargetType="x:Type Button". Note that if you target a type, you can't inherit from a style that targeted another type, so take care in building your styles up properly.
Setters give you the most basic functionality in a style. <Setter Property="Background" value="Red"> will cause any control that uses that style and doesn't override Background to have a Red background. By splitting Value out into another tag you can also get more advanced behaviour <Setter Property="Background"> <Setter.Value> <LinearGradientBrush>
Triggers allow you to change the look, or add animations when properties are certain values or events are triggered. By allowing us to do a lot more visual work in the XAML, we are getting closer to the true separation of GUI and code behind. In Winforms we have a lot of code behind to keep the application looking right, but with XAML it's more than likely possible to keep most of that code in nice clean XAML.
To perform an animation based on an event like Loaded or Click <Style.Triggers> <EventTrigger RoutedEvent="Click"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard> <ColorAnimation>
To have a Trigger based on a property choose <Trigger Property="Control.IsMouseOver" Value="true"> <Setter Property="Background" Value="Red"> <Trigger.EnterActions>... <Trigger.ExitActions>. In this case when the property IsMouseOver is true, we can change the background to Red, and when it's false, it will use the default style. Also by adding tags EnterActions and ExitActions we can start animations when the property becomes true and when it becomes false.
Very cool.
Effects
I have only touched upon effects in this example, but like styles, effects are available and work the same for most controls. The beauty of WPF is you learn how to use an effect, then you can use that effect on buttons, panels, textbox's etc, as effects are applicable to the UIElement on which all those controls are based upon. Many effects add to the GUI feature set, such as a blur effect, glow, drop shadow, bevel, emboss. These can also be animated, as shown in this example.
Animation
In XAML, we again have struck gold with animations that can be done without writing a line of code behind or using timers. WPF uses it's internal timeline to get property values from one value to another. And once again, proeperty is fairly vague allowing us to simply make a control disappear by setting it's Opacity from 1 to 0, or it can be setting complex transformations of the control, parallel to other property changes.
To setup an animation we use the Storyboard seen earlier <BeginStoryboard> <Storyboard> <DoubleAnimation TargetName="CloseButton" TargetProperty="Opacity" From="1" to="0" duration="0:0:0.5" autoreverse="false"> ... In this case DoubleAnimation indicates From and To must be a Double, which could be basically <Type>Animation where Type could be Int32, Byte, Color etc. From and To are start and end values, Duration is a time (0.5 seconds here) and AutoReverse indicates once it's finished the animation will happen in the other direction. Also set RepeatBehavior="Forever" if you want this animation to continue. By adding a tag under <Storyboard> for <ParellelTimeline>, we can run several animations at once, so we can make the Border and Foreground change color at the same time.
Transform
The last feature I've added to this sample shows a simple ScaleTransform when a button is clicked. We can rotate, skew or scale using <Button.RenderTransform> after the Button tag, and make it dead easy to give our app a 3D feel.
If you want more than one Transform, your next tag should be <TransformGroup> otherwise add the Transformation tag <ScaleTransform ScaleX="1" ScaleY="1.5">, which in this case stretches the height of the control and all children. You can again animate this by using <DoubleAnimation TargetProperty="RenderTransform.ScaleX" From="1" To="-1">, which will take the width from normal to nothing, to normal but with the control backwards.
Note that the control you are animating must have a ScaleTransform tag for this to work.
Example
There is more detail within this example, but I'm hoping this is easily enough to get your feet wet and start thinking about what is possible with XAML. Enjoy:
<Window x:Class="HelloWorld.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Hello World" Height="500" Width="500"
>
<Window.Resources>
<!-- General style -->
<Style x:Key="GrayGradientStyle" >
<Setter Property="Control.Background">
<!-- Set a standard gray vertical gradient style, which will be inherited -->
<Setter.Value>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="LightGray" Offset="0" />
<GradientStop Color="DarkGray" Offset="0.7" />
<GradientStop Color="Silver" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
<!-- Glow effect used by next style -->
<OuterGlowBitmapEffect x:Key="OuterGlow" x:Name="OuterGlow" GlowColor="Yellow" GlowSize="0" />
<!-- Style to apply for all buttons, inherits GrayGradientStyle -->
<Style x:Key="{x:Type Button}" BasedOn="{StaticResource GrayGradientStyle}" TargetType="{x:Type Button}" >
<Setter Property="Opacity" Value="0.5" />
<Setter Property="Margin" Value="20" />
<Setter Property="Width" Value="100" />
<Setter Property="BitmapEffect" Value="{StaticResource OuterGlow}" />
<Style.Triggers>
<Trigger Property="Button.IsMouseOver" Value="true">
<Setter Property="Foreground" Value="Red" />
<!-- When IsMouseOver is set to true, set the button to full Opacity and show a Yellow glow around the button -->
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ParallelTimeline>
<DoubleAnimation From="0.5" To="1" Duration="0:0:00.5" Storyboard.TargetProperty="Opacity"></DoubleAnimation>
<DoubleAnimation Storyboard.TargetProperty="BitmapEffect.GlowSize" AutoReverse="True" From="0" To="15" Duration="0:0:0.5" />
</ParallelTimeline>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<!-- When IsMouseOver is set back to false, set the button Opacity back to half -->
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation From="1" To="0.5" Duration="0:0:01" Storyboard.TargetProperty="Opacity"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
<!-- Style to apply for the window -->
<Style x:Key="WindowBackground" TargetType="{x:Type Window}">
<Style.Triggers>
<!-- After the form is loaded continually cycle the background colors back and forth between these colors -->
<EventTrigger RoutedEvent="Window.Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard RepeatBehavior="Forever">
<ColorAnimation From="LightBlue" To="LightCoral" Storyboard.TargetProperty="Background.Color" Duration="0:0:10" Timeline.DesiredFrameRate="10" AutoReverse="True" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<!-- Set the style to the above WindowBackground -->
<Window.Style>
<StaticResource ResourceKey="WindowBackground"></StaticResource>
</Window.Style>
<!-- Main controls -->
<StackPanel>
<StackPanel HorizontalAlignment="Center" >
<!-- Hello World Click Me button (automatically picks up Button style) -->
<Button>Click Me
<Button.Triggers>
<!-- When the button is clicked transform the scale of the Hello World border and turn it's opacity to full and back -->
<EventTrigger RoutedEvent="Button.Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<ParallelTimeline>
<DoubleAnimation Storyboard.TargetName="HelloBorder" Storyboard.TargetProperty="RenderTransform.ScaleX" From="0" To="1" Duration="0:0:5" AutoReverse="True" />
<DoubleAnimation Storyboard.TargetName="HelloBorder" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:5" AutoReverse="True" />
</ParallelTimeline>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Button.Triggers>
</Button>
<!-- Hello World box -->
<Border Width="400" Height="300" Name="HelloBorder" BorderBrush="Black" BorderThickness="2" Opacity="0.3" Style="{StaticResource GrayGradientStyle}">
<Border.RenderTransform>
<!-- Will mean Border is invisible due to ScaleX being 0 -->
<ScaleTransform ScaleX="0" ScaleY="1" CenterX="200" />
</Border.RenderTransform>
<TextBlock Width="400" Height="300" Name="HelloText" TextWrapping="Wrap" FontSize="100" TextAlignment="Center">
<TextBlock.Foreground>
<!-- Set a nice radial gradient for the Hello World text -->
<RadialGradientBrush GradientOrigin="0.5,0.5" Center="0.5,0.5" RadiusX="1" RadiusY="1">
<GradientStop Color="Yellow" Offset="0.2" />
<GradientStop Color="Orange" Offset="0.5" />
<GradientStop Color="Red" Offset="1" />
</RadialGradientBrush>
</TextBlock.Foreground>
Hello World
</TextBlock>
</Border>
</StackPanel>
</StackPanel>
</Window>
Monday, September 18, 2006
Getting started on WPF and .net 3.0 RC1
But for the moment, at RC1, it's probably still a little too risky to fully convert an important machine to Vista, so I'd suggest you get hold of a test machine. Below is some of the software you can use to get you up and running on a test PC, before the .net 3.0 and Vista become official versions.
Vista RC1
I'm very impressed with Vista RC1. It's clearly a "pretty" OS, up there with the latest Mac OS (which I've reluctantly used a bit) and any screenshots I've seen of the fancier Linux OS's. It's features are growing on me, but as a sceptic I'd still say for the vast majority of users there are mild improvements apart from visual ones. With tools like Media Center, DVD authoring, automatic mobile device recognition (eg my PDA) and calender built into the OS, it does avoid a bit of the countless software installs we are used to with a fresh OS, so there is something to be gained from getting Vista.
Go get it now here: http://www.microsoft.com/windowsvista/getready/preview.mspx
Windows Server 2003
Of course if you aren't willing to be a guinea pig for Microsoft, but still want a fresh, legal version of XP for a test machine to try out .net 3.0, Micrsoft is giving out a 6 month trial of Windows server 2003. The beauty of this is you get 6 months uninterupted development on a machine, without Vista complaining that the shipped version is out. You also get a stable fast OS that will run all the .net 3.0 goodness. Not a bad option for a test PC.
Windows Server 2003 180 day trial: http://www.microsoft.com/windowsserver2003/evaluation/trial/default.mspx
Visual Studio trial
Microsoft have of course outdone themselves with the Express editions of Visual Studio. And I'm sure these will include Visual WPF tools later on, but for now WPF programming is best done in Visual Studio from what I've been told.
Again if you don't have this already, Microsoft has 180 day trial for you:
http://msdn.microsoft.com/vstudio/products/trial/
Windows .net 3.0 SDK:
A must for developing applications in .net 3.0 is the SDK itself:
http://www.microsoft.com/downloads/details.aspx?FamilyId=117ECFD3-98AD-4D67-87D2-E95A8407FA86&displaylang=en
Visual Studio Extensions
The extensions for Visual Studio setup all the test projects, so rather than starting with empty projects you can start a new WPF project, which makes life that little bit easier.
The .net 3.0 Visual Studio extensions (RC1):
http://www.microsoft.com/downloads/details.aspx?FamilyId=935AABF9-D1D0-4FC9-B443-877D8EA6EAB8&displaylang=en
WPF
I'm more than interested in WPF than the rest of .net 3.0 at the moment, so here are a couple of tasters that I will be reading over the next few days/weeks also. I'm sure there is way more out there, but for now there is more than enough to get you started. I will be putting my own articles on this blog also, to hopefully go through some of the features in a simplified way.
Here is a nice article with an overview to what WPF is all about. There is no real detail, but it does help to get your head around what XAML will look like, and what WPF can do for you:
http://msdn.microsoft.com/windowsvista/reference/default.aspx?pull=/library/en-us/dnlong/html/introducingwpf.asp
This site gives a good all round look at WPF, with plenty of code samples and tutorials to get you started (click on Download Code... for the files and tutorials):
http://wpf.netfx3.com/
Of course all the other .net 3.0 technologies are here too:
http://www.netfx3.com/default.aspx
And one more link to the mother of information about WPF:
http://windowssdk.msdn.microsoft.com/en-us/library/ms754130.aspx
which can be found in your Windows SDK (hopefully this works on other machines):
ms-help://MS.MSSDK.1033/MS.NETFX30SDK.1033/wpf_conceptual/html/f667bd15-2134-41e9-b4af-5ced6fafab5d.htm
I am due to be looking at a lot of this over the next few weeks and will share my findings. Enjoy!
Tuesday, September 12, 2006
Microsoft AJAX is the new Atlas
It's worth a mention that Atlas is changing it's name and is release date is set to late 2006.
In short the new naming is like this:
"Microsoft AJAX Library" for all Atlas client controls
"ASP.NET 2.0 AJAX Extensions" for the asp.net server side Atlas controls
"ASP.NET AJAX Control Toolkit" for the current Atlas control toolkit
Of course I'm getting all this from the wonderful ScottGu blog article:
http://weblogs.asp.net/scottgu/archive/2006/09/11/_2200_Atlas_2200_-1.0-Naming-and-Roadmap.aspx
Why is it that this naming bugs me? Beta technologies always have the cool and unusual names, whereas the final product is usually so plain and boring.
I can only imagine that searches will be slower and more painful with this new naming. Put "Atlas C#" and other terms into a search engine you will get your results pretty easily. Put "Microsoft AJAX C#" or "ASP.NET AJAX C#" and you may be confused with other AJAX libraries or articles about AJAX as a technology etc. So with this naming we'll need rock solid intellisense and documentation otherwise our lives just got harder.
And to those that haven't followed the Atlas project, it would simply sound like Microsoft found that AJAX was taking off and quickly tacked a library together and and said "Hey, now we have AJAX... see Microsoft AJAX." The truth is the project has been very well thought out. A free client side library, a free asp.net library and a free community built toolkit. It sounds far too open source and cool to be Microsoft. At least too cool to be "Microsoft AJAX"! I see it as one of those projects, along with the wonderful express products, that really reflects Microsofts future potential as a helping hand to programmers, not an evil dictatorship set to make everyone learn the hard way to code with the highest money outlay.
Oh well, it's only a name in the end, the technology is still cool and I'd still tip it to be the number 1 AJAX library for .net shortly after it's release. Lets hope Scott and the others keep pushing the technology to great heights.
Tuesday, September 05, 2006
C# object arrays BinarySearch, Sort and IComparer
This isn't so much a new or very difficult thing, but it's something I've happened to come across twice recently, and I've needed to dig up the example code both times, so thought I'd add it to my blog for future reference.
Basically, I'm getting much more interested in dealing with object arrays rather than DataSets even in smaller projects. I feel like I have more control over certain things with object arrays, like business logic and customising properties. Now one of my projects was .net 2.0 so I used the generic List<> which was quite nicely put together, but my other project is a 1.1 project, so needed a slightly more outdated method.
I'll explain that one here, and probably add a note about the List<> way to do the same (plus more) next time.
Setting up the object array
For a very basic example I've got a class with a couple of fields in it for an Mp3 list:
public class Mp3Class {
private string _Artist;
private string _Song;
private int _Ranking;
public string Artist { get { return _Artist;} set {_Artist = value;}}
public string Song { get { return _Song;} set {_Song = value;}}
public int Ranking { get { return _Ranking;} set {_Ranking = value;}}
public Mp3Class (string Artist, string Song, int Ranking)
{
_Artist = Artist; _Song = Song; _Ranking = Ranking;
}
}
A basic example to get some data into this would be:
Mp3Class[] mp3s = new Mp3Class[5];
mp3s[0] = new Mp3Class("Cave", "Ship Song", 9);
mp3s[1] = new Mp3Class("Nirvana", "Smells like teen spirit", 3);
mp3s[2] = new Mp3Class("Sonic Youth", "100%", 1);
mp3s[3] = new Mp3Class("Cave", "Red right hand", 4);
mp3s[4] = new Mp3Class("Nirvana", "Heart shaped box", 7);
The Array class
So the thing you really need to get your head around working with arrays of objects is the Array class. It's very similar to working with List<>, but missing a few features. For simple arrays, things like IndexOf, Sort and even BinarySearch can be straight forward, but with object arrays a little more work is needed, but fortunately not too much.
Array.Sort
For sorting our class, there is one big thing that makes it more difficult. Which property do you sort on? In this case all are valid, as you may be ordering by artist, by ranking or even by song, but that means we need to implement another class to help us out. The IComparer interface gives us the ability to sort things how we wish using our objects. Basically, if we want to sort this list by Artist, we can implement an IComparer class which compares the Artist string, and Sort will do the rest, or if we want to sort by Ranking, we can compare the ranking numbers and Sort will do the rest. Here are those two examples:
public class ArtistCompareClass : IComparer
{
int IComparer.Compare(object x, object y)
{
int RetVal = String.Compare((x as Mp3Class).Artist, (y as Mp3Class).Artist, true);
return RetVal;
}
}
public class RankingCompareClass : IComparer
{
int IComparer.Compare(object x, object y)
{
int RetVal = (x as Mp3Class).Ranking - (x as Mp3Class).Ranking;
return RetVal;
}
}
The ArtistCompareClass cheats by using String.Compare (with case insensitivity). IComparer.Compare is simply looking for a negative if the first object should be ordered earlier, 0 if they are the same and a positive number if the 2nd object should be ordered earlier. Passing this object to Array.Sort will sort the array alphabetically by Artist.
The RankingCompareClass implements the same IComparer.Compare, so again, if the first Ranking is smaller it returns a negative, if they are the same a 0, if the 2nd Ranking is smaller a positive. This will order the object array by Ranking.
The call to sort the array will look like this:
Array.Sort(mp3s, new RankingCompareClass());
You now have the mp3s ordered by Ranking.
Array.BinarySearch
The BinarySearch as the name suggests searches the array using the same IComparer (or at least can do it this way). So again IComparer helps us search through an array of objects, when the language would otherwise have no idea of what it's searching for.
Note: Remember these key things when using a BinarySearch:
- You must sort by the IComparer before using BinarySearch
- It won't work (100%) if your "key" is not unique
- If the result is negative, you can do a bitwise operation to see the closest match
- If you are only searching a subset of the array, it will still return the item in the entire array that's a match.
Here are a couple of examples. I'll give you another IComparer which will help do "real" searches easier. In this case we'll send through the ranking as the 2nd parameter rather than a full object. As you can imagine if someone wanted to search for the song with ranking number 5, it's easier to pass through 5 than new Mp3Class("", "", 5):
public class RankingCompareValueClass : IComparer
{
int IComparer.Compare(object x, object y)
{
int RetVal = (x as Mp3Class).Ranking - (int)y;
return RetVal;
}
}
To find the object which matches a search with a ranking of 4 (MatchingObject is 2, which is the 3rd object in the array):
Array.Sort(mp3s, new RankingCompareClass());
int MatchingObject = Array.BinarySearch(mp3s, 5, new RankingCompareValueClass());
MessageBox.Show(mp3s[MatchingObject].Artist + " - " + mp3s[MatchingObject].Song);
If the user tried to search for a ranking of 5, we could take them to the next closest match (MatchingObject is 3, which is the 4th object in the array):
Array.Sort(mp3s, new RankingCompareClass());
int MatchingObject = Array.BinarySearch(mp3s, 5, new RankingCompareValueClass());
if (MatchingObject < matchingobject =" ~MatchingObject;">" - " + mp3s[MatchingObject].Song);
That's about it. It's worth pointing out that List<> does most of this stuff plus more, and is slightly easier to use, so I'd tend to use that for any 2.0+ projects.
Tuesday, August 29, 2006
Atlas HoverMenuExtender example
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.
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.
- Add an Atlas ScriptManager to the form
- Setup a GridView with an ItemTemplate with many columns
- Add the databinding code how you wish to your data.
- 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
- Make sure the hover panel has Visibility:hidden in the style or style="display:none" in the panel tag
- Add a HoverMenuExtender inside the ItemTemplate
- Set the TargetControlID to the panel you want to permanently display on the grid.
- Set the PopupControlID to the panel you want to show when the mouse hovers over the grid
- Finally set a HoverCssClass for how you want the main grid row to look when hovered over
- PopupPosition dictates on which edge of the TargetControlID you want the popup to appear
- OffsetX, OffsetY say how far down and right to place the popup from PopupPosition.
- PopDelay means how long the popup will show once the mouse leaves the control. Set this to a low amount on grids.
<%@ 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>
Tuesday, August 22, 2006
Atlas Extender with code behind
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.
- Add an atlas ScriptManager to a webform.
- Drag an atlas DragPanelExtender onto the form.
- Double click on the form to create a Page_Load method in your code behind.
- 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.
- Add these to the form.
- 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.
- Link this to the control to the extender by adding the object to the TargetProperties collection.
- 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>
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:
- Add an Atlas ScriptManager to the form.
- Drag a ConfirmButtonExtender onto a web form.
- 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.
- Drag an asp:Button onto the web form. Call it “AtlasBtn”.
- Goto the Source view and find the ConfirmButtonExtender.
- Start adding a new tag in the middle of that tag by pressing “<”. IntelliSense should kick in and show cc1:ConfirmButtonProperties
- 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
<%@ 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>
Tuesday, August 15, 2006
Why I'm here.
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.