top button
Flag Notify
    Connect to us
      Site Registration

Site Registration

How to Create Sticky Notes in Silverlight?

+4 votes
521 views

This is a widget we are going to make; which has same functionalities as Sticky Note

StickyNoteWidget1.gif

Steps

To begin with we need the following requirements:

  1. Silverlight 3

  2. Visual Studio 2008 SP1

  3. Expression Blend 3

Creating a Silverlight Project with or without RIA enabled.

  1. Create project in Visual Studio and open the solution in Expression Blend 3.

  2. The following figure will guide you for that.

StickyNoteWidget2.gif


StickyNoteWidget3.gif


Designing the User Control in Expression Blend 3

While designing, our main aim is to display the notes which will have a background almost similar to sticky note. So we need a background picture (Sticky Note) in any format (JPEG/PNG). For this example I have used PNG format file as it mixes with the background very easily.

StickyNoteWidget4.gif

Figure 1.4 Sticky Note Background.

Now the big task is to displaying the data in right areas. Like the current date on the top left, a list box which will contain all the notes, one textbox to enter notes, and two buttons to add & delete notes. We have used grid to contain the data and fulfill our aim. The following figure describes everything.

StickyNoteWidget5.gif


Now we can keep our respective controls (Text Block, List Box, Text Box, Images) into our specific areas. After putting it all together it will look like the following figure.

StickyNoteWidget6.gif

The XAML will look like the following after all the design changes above.

<UserControl xmlns:dataControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.DataForm" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"x:Class="StickyNotesSilverlight.MainPage" 
    Width="Auto" Height="Auto" mc:Ignorable="d">
    <Grid Width="277" Height="215">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="0.116*"/>
            <ColumnDefinition Width="0.491*"/>
            <ColumnDefinition Width="0.116*"/>
            <ColumnDefinition Width="0.116*"/>
            <ColumnDefinition Width="0.162*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="0.074*"/>
            <RowDefinition Height="0.074*"/>
            <RowDefinition Height="0.595*"/>
            <RowDefinition Height="0.149*"/>
            <RowDefinition Height="0.107*"/>
        </Grid.RowDefinitions>
        <Canvas Grid.ColumnSpan="5" Grid.RowSpan="5">
            <Image Source="images/stickynote.png"/>

        </Canvas>
        <Grid Margin="8,8,13,-8" Grid.ColumnSpan="5" Grid.RowSpan="4"/>
        <ListBox x:Name="listNotes" Margin="0,0,21,0" Grid.Column="1" Grid.Row="2"BorderThickness="0,0,0,0" Grid.ColumnSpan="4">
            <ListBox.Background>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                    <GradientStop Color="#FFFFF5AA"/>
                    <GradientStop Color="#FFFFF072" Offset="1"/>
                </LinearGradientBrush>
            </ListBox.Background>
        </ListBox>
        <TextBlock x:Name="noteDate" FontSize="14" Grid.Column="1" Grid.Row="1" Text=""TextWrapping="Wrap" Margin="0,0,-4,0" Grid.ColumnSpan="3"/>
        <Image x:Name="addImage" Source="images/add.png" Grid.Column="2" Grid.Row="3"MouseLeftButtonDown="addImage_MouseLeftButtonDown"/>
        <Image x:Name="deleteImage" Source="images/delete.png" Grid.Column="3"Grid.Row="3" MouseLeftButtonDown="deleteImage_MouseLeftButtonDown"/>
        <TextBox x:Name="txtNote" Grid.Column="1" Grid.Row="3" Text="" TextWrapping="Wrap"Background="#FFFDEE70" Height="22" KeyDown="txtNote_KeyDown"/>

    </Grid>
</UserControl>

Adding events to the controls and displaying data.

Now we have a handful of controls in our application. We have txtNote, addIMage, deleteImage to display the data and we have list box control.
The following code explains itself as what are the events and when will it be fired.

namespace StickyNotesSilverlight
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
            //noteDate--->Header of the Stickynote displaying date
            //addImage--->Add Image Button to add one item to list
            //deleteImage--->Delete Image Button to delete one selected item from the list
            //txtNote--->TextBox from where the text will be taken to listbox
            //listNotes--->ListBox that contains all note texts
            noteDate.Text = DateTime.Now.Day.ToString() + "." + DateTime.Now.Month.ToString() + "." + DateTime.Now.Year.ToString();

         }

        private void addImage_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (txtNote.Text != "")
            {
                listNotes.Items.Add(txtNote.Text);
                txtNote.Text = "";
            }
        }

        private void deleteImage_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (listNotes.SelectedItem != null)
            {
                listNotes.Items.Remove(listNotes.SelectedItem);
           }

         }

        private void txtNote_KeyDown(object sender, KeyEventArgs e
        {
            if (e.Key == Key.Enter)
            {
                if (txtNote.Text != "")
                {
                    listNotes.Items.Add(txtNote.Text);
                    txtNote.Text = "";
                }
            }

         }
    }
}

Now run the application and enjoy Sticky Notes Widget.

posted Nov 30, 2015 by Jdk

  Promote This Article
Facebook Share Button Twitter Share Button LinkedIn Share Button


Related Articles

This tutorial shows you how to create an animation of a ball being thrown across the screen, landing and bouncing.

Step by Step Tutorial

A brief description of how to use the article or code. The class names, the methods and properties, any tric

  1. Create a new project in Expression Blend. 
     
  2. Draw an ellipse and name the ellipse "ball" 

    image001.jpg
     
  3. The key to creating a bounce effect is to realize that in physics the vertical motion of a ball in motion is completely independent of the horizontal motion. What we're going to do is create two separate story boards for each of these independent motions and then we're going to go into the XAML and combine them into one storyboard. 
     
  4. Create a new storyboard called "Bounce" 
     
  5. Record a keyframe at time 0 for the ball to capture the current position. Then drag the yellow timeline bar to the 1 second position. 

    image002.jpg

 

  1. Now drag the red ball directly up. And record a key frame. At the one second point. Hit play and you should see the ball move directly up at a smooth rate and then stop. 

    image003.jpg

 

  1. Now let's add some gravity. Click on the second keyframe bubble of the storyboard. Set the easing as shown below. This will make the motion slow down as the ball gets to the top of its motion. Confirm this by playing the storyboard. Once you've confirmed this close out the storyboard. 

    image004.jpg

 

  1. Create a storyboard called Horizontal. Create a keyframe at 0 seconds, and then set the timeline to 2 seconds. Drag the ball horizontally to the right and create a keyframe at the 2 second point. Close out the storyboard. 

    image005.jpg

 

  1. Now let's look at the XAML for the Bounce storyboard. Unless you drug the ball perfectly vertically you'll have two sections in the storyboard, one for animating the x direction and one for animation the y direction. You can tell which is which by looking for the line that ends TranslateTransform.Y or TranslateTransform.X. Delete the section that handles the X motion. 
     
  2. Now let's make the ball return to it's starting point. 

    Here's the XAML before hand:

    image006.jpg

    Notice it's moving the ball from a position of 0 to a position of -206 in 1 second. ControlPoint1's value of 0,1 indicates we are going to start at full speed and reach minimum speed at the end of the motion. To make the ball return back down we'll copy the second keyframe, change to time of the key to 2 seconds, change the destination of the animation to 0, and we'll reverse the sense of the easing defined by ControlPoint2. The results are as follows:

    image007.jpg

    Select the bounce storyboard and hit play. You should see the ball go up and down as if it's been thrown up and down.
     
  3. Now let's add the X motion. Take a look at second storyboard we made earlier called horizontal. Copy the DoubleAnimationUsingKeyFrames section that ends TranslateTransform.X and paste it into the Bounce storyboard. Open the bounce storyboard from the design review and hit play. You should see the ball move in a nice smooth arc as if it has been thrown. 

    image008.jpg

 

 

  1. To add a bounce we simply follow the same pattern and add additional key frames. To the DoubleAnimationUsingKeyFrames section that ends TranslateTransform.X add one more keyframe at 3 seconds by adding the following XAML: 

    <SplineDoubleKeyFrame KeyTime="00:00:03" Value="320"/>

    This XAML sets the position that the ball will move to at the end of the third second to 320 which is 22 to the right of where it was in at the end of the previous keyframe. For the vertical portion of the bounce copy the last two keyframes of the DoubleAnimationUsingKeyFrames section that ends TranslateTransform.Y. Set the keyframe time for the peak of the bounce to 2.5 seconds and a height of -20. Have the bounce return to 0 at 3 seconds. This results in the addition of the following XAML:

    <SplineDoubleKeyFrame KeyTime="00:00:02.5" Value="-20">
    <SplineDoubleKeyFrame.KeySpline>
    <KeySpline ControlPoint1="0,1" ControlPoint2="1,1"/>
    </SplineDoubleKeyFrame.KeySpline>
    </SplineDoubleKeyFrame>
    <SplineDoubleKeyFrame KeyTime="00:00:03" Value="0">
    <SplineDoubleKeyFrame.KeySpline>
    <KeySpline ControlPoint1="1,0" ControlPoint2="1,1"/>
    </SplineDoubleKeyFrame.KeySpline>
     
  2. To make the throw occur over and over add a RepeatBehavior to the Storyboard. 

    <Storyboard RepeatBehavior="Forever" x:Name="Bounce">
     
  3. Finally let's add code to start the throw on the load of the page 

    public Page() 

    // Required to initialize variables 
    InitializeComponent(); 
    Loaded += new RoutedEventHandler(PageLoaded); 


    void PageLoaded(object sender, RoutedEventArgs e) 

    Bounce.Begin(); 
    }

     
  4. That's it. Hit F5 and you should see the ball being thrown and bouncing.
READ MORE

Its important that when you think in terms of Silverlight controls, you always think in terms of XAML and that means thinking in terms of a Visual Tree.  Elements in the tree have parents and elements in the tree have children.  A popup control is no  different. Although it appears to look like this disassociated control floating around, it really is just another element in the Visual Tree (Unbeknownst to the naked eye).

In order to position a popup relative to an existing control, you should make it a child of the control.   If the control does not allow children, then put the control in a Grid and you can have all the children you want.  Here is an example.
 

  private void OnHoverTab(object sender, MouseEventArgs e)

  {

  var p = new Popup();

  p.DataContext = ((sender as FrameworkElement).Parent as  
            FrameworkElement).DataContext;

  p.Child = new UnderlyingUserControl();  // puts a user control in the popup

  p.VerticalOffset = 25; // this will offset us slightly from the
                          // parent

  p.HorizontalOffset = 0;

  p.IsOpen = true;

   // this is where we add the popup to a Grid we can position
   // against

  ((sender as FrameworkElement).Parent as Grid).Children.Add(p);

  }



Now once we dismiss our popup, it's important to remove it from the Grid, otherwise we'll end up with lots and lots of dead popups in our Grid tree.

I've added an OK and Cancel onto my Underlying user control to dismiss the popup, here is the code behind for the Child of the popup:
 

  private void OnOK(object sender, RoutedEventArgs e)

    {

      ((MyViewModel) DataContext).Name = NameInput.Text;

// Hide the popup and remove from the parent

      (this.Parent as Popup).IsOpen = false;

      ((this.Parent as Popup).Parent as  Grid).Children.Remove(this.Parent asPopup);

    }

 

    private void OnCancel(object sender, RoutedEventArgs e)

    {

    // Hide the popup and remove from the parent

      (this.Parent as Popup).IsOpen = false;

      ((this.Parent as Popup).Parent as Grid).Children.Remove(this.Parent as Popup);

    }

 

READ MORE

Introduction

If you are developing a Silverlight Application, and you need to pass some parameters inside – for example a key and value pair then we can pass the key value pair from the aspx page itself. We will see how we can do this in Silverlight.

Create a Silverlight Project



Figure 1.1 Creating Silverlight Project

Adding parameters

Open the "InitializingParametersTestPage.aspx" and find the tag tag  <asp:Silverlight  add an attribute InitParameters
Enter the following code to the tag

InitParameters="Key1=Value1,Key2=Value2"

Defining the Parameters

In App.xaml.cs add an object of IDictionary<string,string> as follows

public IDictionary<string, string> AppParams;
In Application_Startup event initialize the parameters as follows
private void Application_Startup(object sender, StartupEventArgs e)
        {
            AppParams = e.InitParams;
            this.RootVisual = new Page();
        }

Using Parameters

In Page.xaml add ListBoxes to show the parameter values
Xaml Code

<UserControl x:Class="InitializingParameters.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml
    Width="400" Height="300">
    <Grid x:Name="LayoutRoot" Background="#FFB7C2E5">
                <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="0.472*"/>
                                <ColumnDefinition Width="0.025*"/>
                                <ColumnDefinition Width="0.502*"/>
                </Grid.ColumnDefinitions>
        <ListBox x:Name="myKeysList"/>
        <ListBox x:Name="myValuesList" Grid.Column="2"/>
    </Grid>
</UserControl>

In code behind of the Page.xaml.cs add the following code to bind the parameters

namespace InitializingParameters
{
    public partial class Page : UserControl
    {
        public Page()
        {
            InitializeComponent();
            App myApp = App.Current as App;

            foreach (string item in myApp.AppParams.Keys)
            {
                myKeysList.Items.Add(item);
            }
            foreach (string item1 in myApp.AppParams.Values)
            {
                myValuesList.Items.Add(item1);
            }
        }
    }
}

Runnning the Application

When you run the application the list will carry the key and value pairs.



Figure 1.2 Displaying Key Value pair

READ MORE

In this article we will explore on Pie Chart in Silverlight 3. Pie Chart comes with Silverlight 3 Toolkit.

Crating Silverlight Project

Fire up Expression Blend 3 and create a Silverlight Application. Name it as PieChartInSL3.

PieChartImg1.gif

 

Go ahead and add a Pie Series into your application.

You can find it in Asset Library.

PieChartImg2.gif

By adding a Pie Series, you just added an Assembly System.Windows.Controls.DataVisualization.

And Blend automatically refers to the Namespace.

If you see the xaml code behind you will find the following:

xmlns:chartingToolkit="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"

Now we will add some data into it.

Create a class called Appointment and add the following code into it.

public class Appointment

    {

        public int Id { get; set; }

        public string AppName { get; set; }

        public string AppointmentDetails { get; set; }

        public int Duration { get; set; }

 

        public Appointment()

        {

        }

 

        public Appointment(int id, string appName, string appointmentDetails, int duration)

        {

            Id = id;

            AppName = appName;

            AppointmentDetails = appointmentDetails;

            Duration = duration;

        }

 

    }

Pie Series takes Key Value pair as it's data. So we will create a class named AppointmentHelper which will convert a Dictionary to Key Value Pair.

 

public static Dictionary<String, int> GetTimeDistribution(this List<Appointment> appts)

        {

            Dictionary<String, int> myTimeDistribution = new Dictionary<string, int>();

 

            var appointments = (from time in appts

                                select time.AppName).Distinct();

 

            foreach (var app in appointments)

            {

                var time = (from pjts in appts

                            where pjts.AppName == app

                            select pjts.Duration).Sum();

 

                myTimeDistribution.Add(app, time);

 

            }

            return myTimeDistribution;

        }

 

Now we will add values.

List<Appointment> appointments;

 

                                public MainPage()

                                {

                                                InitializeComponent();

                CreateTimeLists();

                                }

 

        private List<AppointmentDTO> CreateTimeLists()

        {

            appointments = new List<Appointment>

            {

                new Appointment { Id=1, AppName="Meeting", AppointmentDetails="Video COnference", Duration=30},

                new Appointment { Id=1, AppName="Call", AppointmentDetails="Audio COnference", Duration=90},

                new Appointment { Id=1, AppName="Session", AppointmentDetails="Session for Silverlight", Duration=120}

            };

            return appointments;

        }

Now we will bind our data to Pie Series.

<chartingToolkit:Chart x:Name="TypicalChart" Title="Typical Pie Chart">

            <chartingToolkit:Chart.Series>

                <chartingToolkit:PieSeries Margin="0,0,20,20" d:LayoutOverrides="Width, Height" Title="Pie Chart Sample"IndependentValueBinding="{Binding Path=Key}"

                    DependentValueBinding="{Binding Path=Value}"/>

            </chartingToolkit:Chart.Series>

        </chartingToolkit:Chart>

As you see from the above code I have added two properties as IndependentValueBinding and DependentValueBinding. We need to give the Binding Path to respective key and value.

Now Type cast the chart to Pie Series and assign the ItemSource property.

private void UserControl_Loaded(object sender, RoutedEventArgs e)

        {

            ((PieSeries)TypicalChart.Series[0]).ItemsSource = appointments.GetTimeDistribution();

        }

 

Now go ahead run the application to see the Pie Chart.

PieChartImg3.gif

That's it you have successfully used Pie Series in Silverlight 3.

READ MORE

This article demonstrates how to create and use an image brush in Silverlight using XAML and C#.

Image Brush

An image brush paints an area with an image. The ImageSource property represents the image to be used during the painting by an image brush. The ImageBrush object represents an image brush. 

Creating an Image Brush

The ImageBrush element in XAML creates an image brush. The ImageSource property of the ImageBrush represents the image used in the painting process.

The following code snippet creates an image brush and sets the ImageSource property to an image.

<ImageBrush ImageSource="dock.jpg" />

We can fill a shape with an image brush by setting a shape's Fill property to the image brush. The code snippet in Listing 1 creates a rectangle shape sets the Fill property to an ImageBrush.

<Rectangle

    Width="200"

    Height="100"

    Stroke="Black"

    StrokeThickness="4">

    <Rectangle.Fill>

        <ImageBrush ImageSource="dock.jpg" />

    </Rectangle.Fill>

</Rectangle>

Listing 1

The output looks like Figure 1.

 

ImageBrush1.gif

Figure 1

The CreateAnImageBrush method listed in Listing 2 draws same rectangle with an image brush in Figure 1 dynamically.

/// <summary>

/// Fills a rectangle with an ImageBrush

/// </summary>

public void CreateAnImageBrush()

{

    // Create a Rectangle

    Rectangle blueRectangle = new Rectangle();

    blueRectangle.Height = 100;

    blueRectangle.Width = 200;

 

    // Create an ImageBrush

    ImageBrush imgBrush = new ImageBrush();

 

    imgBrush.ImageSource =

        new BitmapImage(new Uri(@"Dock.jpg", UriKind.Relative));

 

    // Fill rectangle with an ImageBrush

    blueRectangle.Fill = imgBrush;

 

    // Add Rectangle to the Grid.

    LayoutRoot.Children.Add(blueRectangle);

}

Listing 2

Summary

In this article, we saw how to create and use an image brush in Silverlight using XAML and C#.

READ MORE

I am sure that many of you have read about Silverlight, the latest offering from Microsoft promising the ability to deliver rich interactive applications and media. Silverlight 1.1 Alpha has just been released and with this in mind, I decided to download all the tools required to start using Silverlight. To be honest, I have not spent much time looking into Silverlight 1.0; I just couldn't bring myself to start coding heavily in JavaScript. Version 1.1 gives the ability to perform the 'behind the scenes' coding in languages such as C# and VB.NET (plus others).

Having downloaded Silverlight 1.1, Visual Studio 2008 Beta 2 and Expression Blend, I started looking at development. One thing that becomes apparent very quickly is the lack of any form of controls, this is after all an Alpha release and I am sure this will change very soon. You can download the Silverlight 1.1 SDK which does provide controls such as a button, scrollbar, list box, etc. Ever the developer, I decided to have a go at implementing my own simple button control and this article is the result of my development work so far.

The Visual Studio solution file accompanying this article was produced using Visual Studio 2008 Beta 2. I am using the Standard Edition, which weighs in at around 700+ Mb as an ISO file.  It is possible to use Visual Studio 2005 with a little tweaking of a solution file, information on how to do this is readily available on the net.

The Button Control

It is fair to say that this is a very simple control; it's not a particularly pretty looking button. The sole purpose of the exercise was to see how complex implementing your own control was. The button has a rollover effect and animates upon being clicked, this to me is good enough for a simple button.

button1.jpg
Figure 1 - No roll over effect

button2.jpg
Figure 2 - Roll over effect (notice the shade of blue around the edge)

There are two elements to this button, the XAML which defines the look of the button (rectangles and colours, etc) and the 'code behind' the XAML. I used Expression Blend to produce the XAML and then tweaked it by hand. I am not going to show the whole XAML for the button within the article as there is a fair amount of it, but I will be explaining the pertinent parts of it.

The XAML

I generated the layout of the button first, this obviously gave me something to work with when adding functionality, such as events, etc. Below is the XAML for defining the button rectangle.

<Rectangle Width="180" Height="34" RadiusX="5" RadiusY="5"
 StrokeThickness="1" Stroke="#FF0E0E0E" x:Name="ButtonRectangle" >
  <Rectangle.Fill>
    <LinearGradientBrush EndPoint="0,0" StartPoint="0,1">
      <GradientStop Color="#00909194" Offset="0"/>
      <GradientStop Color="#FF979391" Offset="1"/>
    </LinearGradientBrush>
  </Rectangle.Fill>
</Rectangle>

This defines the button outline and gradient fills the rectangle gray. The edges of the rectangle are also rounded.

The next thing we need for our button is text. Text is displayed using a <TextBlock>. The XAML for this is as follows:

<TextBlock x:Name="ButtonText" Canvas.Left="8" Canvas.Top="5"
 Foreground="#FF101010" Text="Button" FontFamily="Arial" FontWeight="Normal"
 FontSize="12" />

In this version of the button, I have hardcoded the font type and size, but ideally this would be set using properties. The layout of the text on the button surface is performed in code. When the button is clicked, to simulate the button looking like it has been pressed, the X and Y position is adjusted. To adjust the position, I am applying a transform. The XAML for this is as follows:

<Canvas.RenderTransform>
  <TransformGroup>
    <TranslateTransform x:Name="buttonPress" X="0" Y="0" />
  </TransformGroup>
</Canvas.RenderTransform>

As it stands, this transform is doing nothing as X and Y are set to 0. These values are changed programmatically to simulate the press, more on this later.

The Roll over effect

As you saw in figure 2 above, when the mouse pointer is over the button, the edges of the button glow blue. This is very simple to achieve using two rectangles similar to the button surface. Each rectangle is of a slightly smaller size. The two rectangles are defined within their own Canvas. This time the opacity is set as essentially the rectangles are placed over the top of our text. You will notice in the Canvas tag, the Visibility is set to collapsed. We only want the glow to be visible when the mouse pointer is over the button. The glow visibility is changed within code.

Our XAML for the glow effect is:

<Canvas x:Name="MouseOver" Canvas.Top="0" Canvas.Left="0" Width="180"
  Height="34" Visibility="Collapsed">
  <Rectangle Width="178" Height="32" Stroke="#FFB0DAEE" Canvas.Top="1"
    Canvas.Left="1" Opacity=".5" x:Name="MouseOverRectangle1" RadiusX="5"
    RadiusY="5" >
    <Rectangle.Fill>
      <LinearGradientBrush EndPoint="0,0" StartPoint="0,1">
        <GradientStop Color="#00909194" Offset="0"/>
        <GradientStop Color="#FF979391" Offset="1"/>
      </LinearGradientBrush>
    </Rectangle.Fill>
  </Rectangle>
  <Rectangle Width="176" Height="30" Stroke="#FFB0DAEE" Canvas.Top="2"
    Canvas.Left="2" Opacity=".5" x:Name="MouseOverRectangle2" RadiusX="5"
    RadiusY="5" >
    <Rectangle.Fill>
      <LinearGradientBrush EndPoint="0,0" StartPoint="0,1">
        <GradientStop Color="#00909194" Offset="0"/>
        <GradientStop Color="#FF979391" Offset="1"/>
      </LinearGradientBrush>
    </Rectangle.Fill>
  </Rectangle>
</Canvas>

As you can see, the rectangles are almost exactly the same as the button surface. The complete XAML for the button can be found in the MyControl project in MyButton.xaml.

The control code

Now we come on to the C# code for the button. Anyone at ease with writing web custom controls, etc will feel quite at home with coding Silverlight controls. All controls inherit from Control.  To ease the creation of a control, within your Visual Studio solution, create a new Silverlight class and then to that project, right click on the project and select Add => New Item and then select Silverlight User Control. This generates boilerplate XAML and a class enabling you to add your code.

As with all controls, we will be needing properties; our properties will be to set the width and height of the control and also the text appearing on the button. To make the button worthwhile, we will also need to be able to respond to a click event, more on this a little later. Now let's get on with some code.

Within the class, I have defined some private variables and one public event. Our private variables allow us to address individual elements within the XAML.  The first two lines of code within the constructor are generated for us by Visual Studio, these lines of code basically load in the XAML for the control from the assembly. The second line of code that defines actualControl allows us to reference the control and to set references to each of the elements in our XAML. For example, doing the following:

buttonRectangle = actualControl.FindName("ButtonRectangle") as Rectangle;

Will allow us to access the attributes of our button surface.

The rest of the code sets up event handlers for handling the mouse events for our button. A call to UpdateButton is then made. let's take a look at UpdateButton.

buttonRectangle = actualControl.FindName("ButtonRectangle") as Rectangle;
mouseOverRectangle1 = actualControl.FindName("MouseOverRectangle1") as Rectangle;
mouseOverRectangle2 = actualControl.FindName("MouseOverRectangle2") as Rectangle;
mouseOverCanvas = actualControl.FindName("MouseOver") as Canvas;
TextBlock btnText = actualControl.FindName("ButtonText") as TextBlock;

buttonRectangle.Width = _width;
buttonRectangle.Height = _height;
mouseOverRectangle1.Width = _width - 2;
mouseOverRectangle1.Height = _height - 2;
mouseOverRectangle2.Width = _width - 4;
mouseOverRectangle2.Height = _height - 4;

btnText.Text = _buttonText;
double left = (buttonRectangle.Width - btnText.ActualWidth) / 2;
double top = (buttonRectangle.Height - btnText.ActualHeight) / 2;
btnText.SetValue<double>(Canvas.TopProperty, top);
btnText.SetValue<double>(Canvas.LeftProperty, left);

The first 5 lines of code assign references to individual elements defined within the XAML.  After this, we are then setting the width and height of the button surface rectangle and the 2 mouse over rectangles, also not forgetting setting the text we want displayed on the button. We then perform some simple maths to centre the text onto the button surface.

A note on inherited Properties

This class implements the properties Width and Height, so to use these in our control should be a simple matter of doing the following:

public new double Width
{
 get { . . . }
 set { . . . }
}

And in reality it is, but there is a bug in the current Alpha release. If you create an instance of your control in XAML and set the width, it will not be set. If you set the width in code, it works fine, when we come to write code to test our control, I will show you exactly the impact this has. To overcome the problem of setting the buttons text within XAML, I have created the property ButtonText which will allow the buttons text to be defined. Note that within the setter for all the properties, the UpdateButton method is being called; this is because different attributes of the button are being set and we want this reflected in the rendered button.

Mouse events

At the beginning of the article, I mentioned that the control declares a public event called Click. The reason I have done this is because I want to emulate the way controls work in general and 99% of controls have a click event. There is also another reason for this. Within Silverlight, there are two events that are fired when a mouse button is clicked, these are MouseLeftButtonDown and MouseLeftButtonUp. Neither of these two events, on their own, gives the desired click behaviour. What I want to achieve with the Click event is to check if the mouse pointer is over the button when the left button is released. Two other mouse events come into play here, these being MouseEnter and MouseLeave. Let's take a look at what each of these events is doing.

MouseEnter
Within the code, there is a Boolean variable called isPressed. When the left mouse button is pressed this is set to true. When the mouse pointer first enters the button surface we set this variable to false. As we are within the button surface, we want to make the button glow; basically we want to switch on our glow effect. To do this, we simply make the MouseOver canvas  visible, by setting the Visibility attribute to Visibility.Visible. That is all that happens within this event.

MouseLeave
We set isPressed to false. Even if the left mouse button is being held down, if we leave the surface of the button, we do not want the Click event to fire when the button is released, as we are not over the button. We set the MouseOver canvas to Visibility.Collapsed, which hides the canvas. Remember at the beginning of the article we declared a transform within the XMAL which would enable us to animate the button? Well when the mouse leaves the button surface, we want to remove this animation; we simply set the X and Y values of the transform to 0, thus setting the button back to its original position. Even if the button hasn't been pressed and it's still in its original position, we may as well execute this code.

MouseLeftButtonDown
We set isPressed to true, as the mouse button has been pressed. We also increment the X and Y position of the button surface by 2, simulating the button being pressed.

MouseLeftButtonUp
This event holds the key to a correct click event. First we remove the transform on the button as we want it to revert back to its original position. We then check if the button isPressed and the Click event has an event handler 'wired up' to it. If these two conditions are true, we execute the click. We then set isPressed to false.

Testing the control

Within the Visual Studio solution file supplied with this article, there is the project for the actual button and also a project that allows us to test the control. This project was created using the Silverlight Project template. In order to use our new control, there are a couple of things we need to do. First we need to add a reference to our button control; within our test application, we need to right click on the References tree node and when the Add Reference dialog pops up, select the Project tab and select our button project from the list.

When the project was created, some boilerplate XAML was created for the project. This XAML needs to be amended in order to support our control. We need to add an xmlns tag to our XAML to reference the assembly of our control. This takes the form of:

xmlns:MyControls="clr-namespace:MyButton;assembly=ClientBin/MyButton.dll"

With the addition of the above line, the XAML should now look like:

<Canvas x:Name="parentCanvas"
   xmlns="http://schemas.microsoft.com/client/2007
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml
   Loaded="Page_Loaded" 
   x:Class="MyControl.Page;assembly=ClientBin/MyControl.dll"
   xmlns:MyControls="clr-namespace:MyButton;assembly=ClientBin/MyButton.dll"
   Width="640"
   Height="480"
   Background="White">  
</Canvas>

We can now add an instance of our button to the above XAML, the mark-up for our button is:

<MyControls:Button x:Name="Button1" Canvas.Left="20" Canvas.Top="200"  />

This mark-up is placed between the Canvas tag. As with our control, there is an associated C# file where we can manipulate our control programmatically. Within code, we will set the text to be displayed on the button and set its width and height. We will also wire up an event to respond to clicking the button.

Our source code for this is as follows:

Canvas cc = o as Canvas;
MyButton.Button btn = (MyButton.Button)cc.FindName("Button1");
btn.ButtonText = "Press Me!!";
btn.Width = 140;
btn.Height = 35;
btn.Click += delegate(object sender, EventArgs ea)
             {
                btn.ButtonText = "Button Pressed!";
             };

There shouldn't be a great many surprises in the code above. Basically we are setting the text, width and height of the button and wiring-up the Click event. I have wired-up the event the easy way, but it could also have been done as follows:

btn.Click += new EventHandler(btn_Click);

. . .

private void btn_Click(object sender, EventArgs ea)
{
 . . .
}

I did mention the problem with adding inherited properties to the XAML for the button. As an example, the code above sets the width to 140, if I added Width="140" to the XAML, the button would not have rendered correctly. I have blogged about this and an entry can be read on my blog with a link to where I found the information. I am sure this problem will be ironed out in future releases.

READ MORE
...