Sunday, 26 August 2007

How to make a Button in Silverlight 1.1

In my button we will change the color of the canvas in on mouse hover, and allows you to implement the click logic at the TODO.

You can use this code for your own buttons.

The important points are:

MouseEnter - When we hover over the button
MouseLeave - When we stop hovering over the button
MouseLeftButtonDown - When you hold the mouse left button down
MouseLeftButtonUp - When you release the mouse left button.

A click is only considered a click, when you are hovered over the button, and the MouseLeftButtonUp.

On MouseLeftButtonDown you need to capture the mouse input, and release the mouse capture when finished (so mouse input can be capture by other objects at another time, you can only capture mouse input if no other object has captured mouse input).

Finally we do a final cleanup (if necessary) on the canvas to ensure we have released the mouse capture.

One final thing to note, within the XAML for the canvas we use the Cursor attribute to define the mouse cursor to use.

Go Enjoy, and make Buttons (whilst you can), before Microsoft makes it even easier for us :)

Here is the XAML for my Button:



<Canvas xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="550"
Height="40"
Background="DarkBlue"
MouseEnter="MenuItem_MouseEnter"
MouseLeave="MenuItem_MouseLeave"
MouseLeftButtonDown="MenuItem_MouseLeftButtonDown"
MouseLeftButtonUp="MenuItem_MouseLeftButtonUp"
Cursor="Hand"
>
<TextBlock x:Name="tbMenuText" Foreground="White" FontWeight="ExtraBold" FontSize="28"></TextBlock>
</Canvas>


Here is the C# for my Button:



using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace MySilverlightProject.SkyEPG
{
public class MenuItem : Control
{
public MenuItem()
{
System.IO.Stream s = this.GetType().Assembly.GetManifestResourceStream("MySilverlightProject.SkyEPG.MenuItem.xaml");
implementationRoot = this.InitializeFromXaml(new System.IO.StreamReader(s).ReadToEnd());
tbMenuText = implementationRoot.FindName("tbMenuText") as TextBlock;

// Set the root leave
implementationRoot.MouseLeave += MenuItem_OnRootLeave;
}

#region properties
// private members
FrameworkElement implementationRoot;
private TextBlock tbMenuText;

/// <summary>
/// Text
/// </summary>
public string Text
{
get
{
return tbMenuText.Text;
}
set
{
tbMenuText.Text = value;
}
}
#endregion

#region Mouse Handling
// By Default mouse over is false and mouse down is false
bool mouseOver = false;
bool mouseDown = false;

/// <summary>
/// On enter set the color to yellow
/// </summary>
/// <param name="o"></param>
/// <param name="e"></param>
protected void MenuItem_MouseEnter(object o, EventArgs e)
{
// Get the menu item
Canvas menuItem = (Canvas)o;

// We have a mouse over
mouseOver = true;

// Set the background color to gold, text color to dark blue
menuItem.Background = new SolidColorBrush(Color.FromArgb(255, 255, 215, 0));
tbMenuText.Foreground = new SolidColorBrush(Color.FromArgb(255, 0, 0, 139));
}

/// <summary>
/// On leave, set the color back to Dark Blue
/// </summary>
/// <param name="o"></param>
/// <param name="e"></param>
protected void MenuItem_MouseLeave(object o, EventArgs e)
{
// Get the menu item
Canvas menuItem = (Canvas)o;

// Set the background color to Dark Blue, text color to white
menuItem.Background = new SolidColorBrush(Color.FromArgb(255, 0, 0, 139));
tbMenuText.Foreground = new SolidColorBrush(Colors.White);

// No Mouse Over
mouseOver = false;
}

/// <summary>
/// Mouse Left Button Down
/// </summary>
/// <param name="o"></param>
/// <param name="e"></param>
protected void MenuItem_MouseLeftButtonDown(object o, MouseEventArgs args)
{
// Mouse Down
mouseDown = true;

// Get the menu item
Canvas menuItem = (Canvas)o;

// Capture the Mouse
menuItem.CaptureMouse();
}

/// <summary>
/// Mouse Left Button Up
/// </summary>
/// <param name="o"></param>
/// <param name="e"></param>
protected void MenuItem_MouseLeftButtonUp(object o, MouseEventArgs args)
{
// Get the menu item
Canvas menuItem = (Canvas)o;

// Release the mouse capture
menuItem.ReleaseMouseCapture();

// Check if we have a click (mouse over, and mouse down)
if (mouseOver)
{
// TODO: Implement Click Logic Here
}

// No Mouse Down
mouseDown = false;
}

/// <summary>
/// When the mouse leaves the root visual we lose the capture - reset the state
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
protected virtual void MenuItem_OnRootLeave(object sender, EventArgs args)
{
// Clean Up
if (mouseOver || mouseDown)
{
// Release Mouse Capture
ReleaseMouseCapture();
mouseDown = false;
mouseOver = false;
}
}
#endregion
}
}

4 comments:

Matthew C. Douglass said...

Ok...so now how would one add a custom Button to a primary xaml page? I'm still in shock that MS wouldn't provide basic textbox/dropdown/button controls, even with an alpha release.

Anonymous said...

It is very easy :)))))))

chrishayuk said...

I'm hoping you are being sarcastic. It is very tough making buttons correctly at the moment, in later refreshes it will become very easy, as we will have a button control (as you have in WPF).

However I think the exercise is useful, as you have deeper understanding of Silverlight

chrishayuk said...

How do you add the button to the page? If you have put this lot into a user control, then you would use the same technique for adding user controls to the page.