Jeff Blankenburg is a passionate technologist with a wide range of interests.
This website is dedicated to discussing the ideas that pass through his head.

The main header for this website was created using Microsoft Silverlight.
Install it to see what you're missing!

Get Silverlight to see the whole site!

Day #4: Communicating Between Two Silverlight Controls

Saturday, July 04, 2009

Have you ever wondered how to get more than one Silverlight element on your page? Have you ever wondered how to get two Silverlight controls to communicate? This post will address both of those questions.

For those of you not pondering those questions, here's a common scenario: You want to have a common Silverlight navigation on your page, and you don't want to redirect the user to another page for each click. Instead, we want a second Silverlight element on the page that changes as we click the nav.

It's generally bad user experience to put everything in one, giant Silverlight container, because it will take FOREVER to load, forcing your users to sit and wait before they can do anything. By being more modular, we improve load times, and it's actually pretty simple to do. Let's get started:

1. Create your Silverlight project.




Make sure you create your accompanying Web project as well..



2. Make this XAML unique.

I'm just going to make the background of the Silverlight app orange. I've also added a "1" so that I'm sure which control it is. When we put 2 Silverlight controls on a page, we want to make sure we know which is which. There are also three buttons on this screen. When the user clicks those buttons, we're going to change the background color of the other Silverlight control. We'll get to the event handler code a little later. (You might also need to add the System.Windows.Browser namespace...it's for talking to the DOM). Here's the XAML I am using:

<UserControl x:Class="SilverlightWithTwoControls.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<
StackPanel x:Name="LayoutRoot" Background="Orange" HorizontalAlignment="Center" VerticalAlignment="Center" Width="400" Height="300">
<
TextBlock Text="1" FontSize="100"></TextBlock>
<
Button x:Name="Green" Content="Green" Width="100" Height="25" Margin="10" Click="Button_Click" />
<
Button x:Name="Purple" Content="Purple" Width="100" Height="25" Margin="10" Click="Button_Click" />
<
Button x:Name="Blue" Content="Blue" Width="100" Height="25" Margin="10" Click="Button_Click" />
</
StackPanel>
</
UserControl>


3. Create another Silverlight project.

Each Silverlight project will be independent of each other. Each Silverlight project creates ONE XAP file, and since we need two, this is the best solution.



4. Mark up our second XAML file.

This file is even simpler. We're only modifying the background color and adding a 2 for identification. Here's the code:

<UserControl x:Class="SecondControl.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<
Canvas x:Name="LayoutRoot" Background="#666666" HorizontalAlignment="Center" VerticalAlignment="Center" Width="400" Height="300">
<
TextBlock Text="2" FontSize="100"></TextBlock>
</
Canvas>
</
UserControl>


5. Let's add these to our .aspx page.

We're just going to have 2 <asp:Silverlight> tags on our page in this example, pointing to the two individual .xap files. Here's what the HTML looks like:

<%@ Page Language="C#" AutoEventWireup="true" %>
<%
@ Register Assembly="System.Web.Silverlight" Namespace="System.Web.UI.SilverlightControls" TagPrefix="asp" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<
html xmlns="http://www.w3.org/1999/xhtml" style="height:100%;">
<
head runat="server">
<
title>Silverlight With Two Controls</title>
</
head>
<
body style="height:100%;margin:0;">
<
form id="form1" runat="server" style="height:100%;">
<
asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
<
div style="position:absolute;top:10px;left:10px;">
<
asp:Silverlight ID="Xaml1" runat="server" Source="/ClientBin/SilverlightWithTwoControls.xap" MinimumVersion="2.0.31005.0" Width="400" Height="300" />
</
div>
<
div style="position:absolute;top:320px;left:10px;">
<
asp:Silverlight ID="Xaml2" runat="server" Source="/ClientBin/SecondControl.xap" MinimumVersion="2.0.31005.0" Width="400" Height="300" />
</
div>
</
form>
</
body>
</
html>


6. Writing the button event handler.

We need those buttons to actually do something. Let's write that event handler code. Here's what it looks like:

private void Button_Click(object sender, RoutedEventArgs e)
{
Button clicky = sender as Button;
HtmlPage.Window.Invoke("changeColor", clicky.Name);
}


7. Say it ain't so...

I don't know how many times I can tell you that Javascript rules the world, but here's another example. We're going to leverage the power of Javascript to talk between our Silverlight objects. Because it has the ability to leverage the Silverlight DOM, it's actually a very useful and powerful tool. (And for all of you naysayers, if a user has Javascript turned off, it's HIGHLY likely they're not running rich UI plugins like Silverlight or Flash either.)

Anyways, there's a pretty simple Javascript function we can write to get this action taken care of. In our previous step, we specified the name of the Javascript function, changeColors. We also pass the Name value of the Button, which just happens to be the name of the color we're going to be changing the other control to. Forethought is cool. Here's what my Javascript function looks like:

function changeColor(color) {
slObject = document.getElementById("Xaml2");
slObject.Content.Page.ChangeBackgroundColor(color);
}


What we've done here is call the method ChangeBackgroundColor inside the Xaml2 control. We're passing the color we want to change it to.

8. Writing the final method in the 2nd control.

Now we just need to write that method in the code-behind of our second XAML file, and we should be done. Here's my final code for the second control:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Browser;

namespace SecondControl
{
public partial class Page : UserControl
{
public Page()
{
InitializeComponent();
}

[ScriptableMember]
public void ChangeBackgroundColor(string colorName)
{
if (colorName == "Blue")
{
LayoutRoot.Background = new SolidColorBrush(Colors.Blue);
}
else if (colorName == "Purple")
{
LayoutRoot.Background = new SolidColorBrush(Colors.Purple);
}
else if (colorName == "Green")
{
LayoutRoot.Background = new SolidColorBrush(Colors.Green);
}
}
}
}


You might have noticed that there's something a little different in there. We have a decorator [ScriptableMember] in there. We had to make some changes to our application to make it exposed to Javascript. By default, it can't just call inside our Silverlight app. We have to make that happen in code.

9. Editing our App.xaml file.

In the second Silverlight project, open your app.xaml file. In our Application_Startup method, you should have a line that looks like
this.RootVisual = new Page();
. We're going to add one more line after that, which registers our control as a Scriptable object. Here's the entire method, after my modifications:

private void Application_Startup(object sender, StartupEventArgs e)
{
this.RootVisual = new Page();
HtmlPage.RegisterScriptableObject("Page", this.RootVisual);
}


This line of code, in conjunction with the decorator we added in Step #8 will mean we're done, and that our controls can now affect each other.

Sample Code

You can download the sample code for this example here. You should also be able to see these controls below this paragraph, but RSS readers like to ignore it. If it's not showing up, you can also see Two Silverlight Controls together by clicking here.










Get Microsoft Silverlight












Get Microsoft Silverlight

Labels: , ,

posted by Jeff Blankenburg, 1:00 AM | link | 0 comments |

Day #3: Custom Silverlight Loading Screen

Friday, July 03, 2009

This is the third post in my series of thirty-one, called, not surprisingly, "31 Days of Silverlight". You can find the master list here.

Also, before we get started here, don't forget that today is Contribupendence Day. Take a moment to read this post about what Contribupedence Day is, and how you can participate.

If you've ever seen a Silverlight application before, you've likely seen the default loading screen. Here's a example of what I'm talking about:



Now, there's nothing wrong with it, except that it's the thing you see EVERYWHERE. There's a way to customize this screen, and you should. It's an opportunity to re-inforce your branding, entertain your user, and differentiate yourself from everyone else. Let's get started.

Building Our Loading Screen

The first thing to know about this loading screen is that it functions completely outside of our .xap file. If you think about it though, it makes sense. We're trying to monitor the loading percentage of our XAP file, so we could hardly expect our loading code to be inside it, right?

So, instead of creating a new XAML file inside of our Silverlight project, we're going to create a XAML file inside our Web Project this time. When you choose "Add > New Item...", you're going to choose the "Silverlight JScript File." This will create a XAML file in our web project, but otherwise, it's your standard XAML. I've created one that has a TextBlock to display the percentage as a number, as well as a rectangle underneath. This rectangle will be my percentage progress bar. Here's the code (I named it LoadingScreen.xaml):

<Canvas xmlns="http://schemas.microsoft.com/client/2007" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="400" Height="300">
<
Canvas x:Name="LayoutRoot" Background="#FFB5EFFF">
<
Rectangle Height="4" Width="0" Fill="#FFE8B03A" Stroke="#FF999999" StrokeThickness="1" x:Name="ProgressBar" Canvas.Left="14" Canvas.Top="156"/>
<
TextBlock Width="100" FontFamily="ROCK.TTF#Rockwell" FontSize="48" Text="Blankenthoughts" Foreground="#FF6D6D6D" x:Name="Title" Canvas.Top="56" Canvas.Left="150" />
</
Canvas>
</
Canvas>


Getting Our Loading Screen Loaded

So we've got a loading screen now, but we also need to make sure that our Silverlight <object> tag knows that we've got a custom loading screen. We do this with a param tag in the HTML. The splashscreensource tag specifies a XAML file that should be used instead of the default. Here's how my entire HTML file looks now:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<
html xmlns="http://www.w3.org/1999/xhtml" >
<
head>
<
title>SilverlightLoadingScreen</title>
</
head>

<
body>
<
div id="silverlightControlHost">
<
object id="xamlobject" data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%">
<
param name="splashscreensource" value="LoadingScreen.xaml"/>
<
param name="source" value="ClientBin/SilverlightLoadingScreen.xap"/>
<
param name="background" value="white" />
</
object>
</
div>
</
body>
</
html>


What you may notice, if you're building along with me, is that the loading screen loads, but it doesn't change as the load progresses. This is because we need to pay attention to the "onSourceDownloadProgressChanged" event. Thankfully, we do with with another param tag in our <object> tag. The value that we provide is actually the name of the Javascript function we will write. That tag looks like this:

<param name="onSourceDownloadProgressChanged" value="onSourceDownloadProgressChanged" />


You didn't tell me there'd be Javascript

Ah, never doubt for a second that the Internet runs on Javascript. Of course it does! This function is simple, and is the glue that puts our XAML together with actual data. I'll give you my function first, and then we can discuss the different parts of it.

function onSourceDownloadProgressChanged(sender, eventArgs)
{
var slObject = document.getElementById("xamlobject");
var progressBar = slObject.content.findName("ProgressBar");
var progressTitle = slObject.content.findName("Title");
if (eventArgs.progress)
{
progressBar.Width = eventArgs.progress * 370;
progressTitle.Text = parseInt(eventArgs.progress * 100) + "%";
}
else
{
progressBar.Width = eventArgs.get_progress() * 370;
progressTitle.Text = parseInt(eventArgs.get_progress() * 100) + "%";
}
}


  • slObject - this is a reference to my Silverlight <object> tag on the page. I need to get this in order to find the child elements, specifically my Rectangle and TextBlock elements.
  • progressBar - this is a reference to my ProgressBar Rectangle element within my XAML document. Don't you wish getting through XML was always that easy? It just searches through the document tree until it finds an element with the name I specified.
  • progressTitle - a TextBlock in the XAML that will hold the actual percentage of completion.
  • eventArgs.progress - this is the physical number that represents our completion percentage. We use this to modify the width of our rectangle, so that it grows as the percentage increases. I am also displaying this number in the TextBlock, appending a "%" to the end.
  • eventArgs.get_progress()
  • - basically, we need to call the get_progress method in case our page is not already paying attention to it. Once this has been called, however, it will default to the previous part of the if statement, using just the progress property of the eventArgs.


Can I See A Working Example?

Absolutely. Below is a working example of this custom loading screen in action. If you don't see it, you're probably reading this post from an RSS reader. Click here to see the Silverlight Loading Screen as a working example. You can also click here to download my entire set of working code.












Get Microsoft Silverlight

Labels: , ,

posted by Jeff Blankenburg, 1:00 AM | link | 2 comments |

Day #2: Silverlight Screen Transitions

Thursday, July 02, 2009

This is second of thirty-one posts on Silverlight I will be doing in July. The first post was on the mouse events available to you in Silverlight. Today's post is on Screen Transitions, or more specifically, moving from one XAML file to another.

Moving From One XAML File To Another

This is the simple part. In your Silverlight project (mine is called SilverlightScreenTransitions), add a new XAML file. You can do this by right clicking on the project name, and choosing "Add > New Item." You won't see "XAML File" as one of the choices, because each XAML file in Silverlight is considered a User Control. So choose "Silverlight User Control," and give it a meaningful name, like page2.xaml. :)

Now jump back into your default XAML file, Page.xaml. We need a button, or a link, or something that will allow us to navigation to our new page. Here's the new XAML for our default page:

<UserControl x:Class="SilverlightScreenTransitions.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<
Canvas x:Name="LayoutRoot" Background="White">
<
Rectangle x:Name="Clicky" Width="200" Height="50" Fill="Red" Canvas.Top="125" Canvas.Left="100" Stroke="Black" StrokeThickness="4" MouseLeftButtonUp="Clicky_MouseLeftButtonUp"/>
</
Canvas>
</
UserControl>


All this does is put a red rectangle in the middle of our control. Next, we're going to need to edit our second page. We'll just put a "Congratulations!" textbox on the page, so we know we made it. Here's the XAML for Page2.xaml:

<UserControl x:Class="SilverlightScreenTransitions.Page2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<
Canvas x:Name="LayoutRoot" Background="White">
<
TextBlock Width="200" Height="50" Canvas.Top="125" Canvas.Left="100" Text="Congratulations!" TextAlignment="Center" FontSize="25"/>
</
Canvas>
</
UserControl>


The magic line of code

At this point, we have two XAML files, one with a rectangle (with an event handler), and the other with just a TextBlock. When we click on the Rectangle, we want to go to the other XAML file. Here's how you do it (in VB.NET, just ignore the semi-colon). Just add this line to your event handler code in Page.xaml.cs (or .vb):

this.Content = new Page2();


I thought this post was about transitions...

Oh, patience, my friends. Now that we know how to get from one screen to another, we can talk about transitions. Let me first start by defining transition:

The animated movement from one XAML file to another. Think transitions in Powerpoint. Fades, Dissolves, etc. We'll create an example of that in this post.

Fading In and Out

We're going to create a fading transition from the first slide to the second. What I'm going to do is create an animation in each XAML file. In Page.xaml, we'll create an animation that fades out. In Page2.xaml, we'll create an animation that fades it in. Between the two, we'll jump from one file to the next, using the code we wrote earlier.

Page.xaml animation

The only difference is the new Storyboard I created. It just takes the opacity of the LayoutRoot element from 100% to 0% in one second:

<UserControl x:Class="SilverlightScreenTransitions.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<
UserControl.Resources>
<
Storyboard x:Name="FadeOut">
<
DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(UIElement.Opacity)">
<
SplineDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
<
SplineDoubleKeyFrame KeyTime="00:00:01" Value="0"/>
</
DoubleAnimationUsingKeyFrames>
</
Storyboard>
</
UserControl.Resources>
<
Canvas x:Name="LayoutRoot" Background="White" Opacity="1">
<
Rectangle x:Name="Clicky" Width="200" Height="50" Fill="Red" Canvas.Top="125" Canvas.Left="100" Stroke="Black" StrokeThickness="4" MouseLeftButtonUp="Clicky_MouseLeftButtonUp"/>
</
Canvas>
</
UserControl>


Page2.xaml animation

We are doing the exact opposite animation for this file, but there's one other thing to consider in this case. Even though our animation takes the opacity from 0% to 100%, we need to make sure that the initial opacity of our LayoutRoot element is set to 0%. Without that, the XAML file will load with it at 100%, and then the animation will kick off, fading it from 0 to 100. Not exactly the desired effect. So you'll see the opacity specified in the LayoutRoot element as well.

<UserControl x:Class="SilverlightScreenTransitions.Page2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<
UserControl.Resources>
<
Storyboard x:Name="FadeIn">
<
DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(UIElement.Opacity)">
<
SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
<
SplineDoubleKeyFrame KeyTime="00:00:01" Value="1"/>
</
DoubleAnimationUsingKeyFrames>
</
Storyboard>
</
UserControl.Resources>
<
Canvas x:Name="LayoutRoot" Background="White" Opacity="0">
<
TextBlock Width="200" Height="50" Canvas.Top="125" Canvas.Left="100" Text="Congratulations!" TextAlignment="Center" FontSize="25"/>
</
Canvas>
</
UserControl>


An Animation Event Handler?

So we obviously also need to change our code-behind, so that when we click, we call the animation. But how do we know when the animation is done? Well, we know it's going to take exactly ONE second, so technically, we could create a timer, wait 1 second, and then make the call to the second XAML file. But that's messy, and depending on ANY sort of lag, would be inaccurate. Thankfully, we have the ability to add event handlers to our animations as well. So, we can create a "Completed" event handler on our FadeOut animation, which will get called immediately after the animation completes. No guess work. Here's our new code-behind:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SilverlightScreenTransitions
{
public partial class Page : UserControl
{
public Page()
{
InitializeComponent();
FadeOut.Completed += new EventHandler(FadeOut_Completed);
}

void FadeOut_Completed(object sender, EventArgs e)
{
this.Content = new Page2();
}

private void Clicky_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
FadeOut.Begin();
}
}
}


Catching the animation on the other side

Transitioning into the next XAML file is simple, in the initial method, we call the FadeOut animation we created.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SilverlightScreenTransitions
{
public partial class Page2 : UserControl
{
public Page2()
{
InitializeComponent();
FadeIn.Begin();
}
}
}


The final working example

Below is the Silverlight application, up and running. If you're viewing this in an RSS reader, it may not show up, but you can click here to see the Silverlight Screen Transition working. You can also download all of the source code for this project here.







Get Microsoft Silverlight

Labels: , ,

posted by Jeff Blankenburg, 1:00 AM | link | 3 comments |

Day #1: Mouse Events in Silverlight

Wednesday, July 01, 2009

In my inaugural post of the "31 Days of Silverlight," we're going to focus on Mouse Event handlers. With an interactive application, you're often going to want to know when your users are clicking on stuff. So, this is a tutorial on the different mouse events, and how to use them. So, let's start with the beginning, and go forward from there. You can download ALL of the sample code from this post here.

MouseEnter

I am going to demonstrate this on two levels. The first will be a MouseEnter event on the Silverlight control as a whole. This event will fire when the user's mouse enters the space that the Silverlight control takes up. We will be putting a second event on a circle that is in the Silverlight application. Here's our starter XAML.

<UserControl x:Class="SilverlightMouseEvents.MouseEnterDemo"
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="White">
<
Ellipse x:Name="myEllipse" Fill="Blue" Width="150" Height="150" />
</
Grid>
</
UserControl>


I am going to add the event handlers to the XAML, but I will show you how to do it in code as well. Here's our modified XAML, with the event handlers inline.
<UserControl x:Class="SilverlightMouseEvents.MouseEnterDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300" MouseEnter="UserControl_MouseEnter">
<
Grid x:Name="LayoutRoot" Background="White">
<
Ellipse x:Name="myEllipse" Fill="Blue" Width="150" Height="150" MouseEnter="myEllipse_MouseEnter" />
</
Grid>
</
UserControl>

Now we need to jump into the code-behind to write the event handler actions. As soon as I created the event handlers in the XAML, it automatically stubbed out the methods for me in code. Here's how my initial C# code-behind looks.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SilverlightMouseEvents
{
public partial class MouseEnterDemo : UserControl
{
public MouseEnterDemo()
{
InitializeComponent();
}

private void UserControl_MouseEnter(object sender, MouseEventArgs e)
{

}

private void myEllipse_MouseEnter(object sender, MouseEventArgs e)
{

}
}
}

In order to keep this post reasonable in length, I'm not going to do anything complicated in my event handling, but I will show you how to change the color of the Ellipse. I've added one line of code to each method, and each one changes the Ellipse to a different color. At this point, when we run our mouse into the Silverlight area of our web page, the circle will change to green, and when we mouse over the circle, it turns purple.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SilverlightMouseEvents
{
public partial class MouseEnterDemo : UserControl
{
public MouseEnterDemo()
{
InitializeComponent();
}

private void UserControl_MouseEnter(object sender, MouseEventArgs e)
{
myEllipse.Fill = new SolidColorBrush(Colors.Green);
}

private void myEllipse_MouseEnter(object sender, MouseEventArgs e)
{
myEllipse.Fill = new SolidColorBrush(Colors.Purple);
}
}
}


MouseLeave

In this case, it's pretty much exactly the same as MouseEnter, but when the mouse LEAVES something. Novel idea, huh? This time, however, I will not have any modifications to my XAML at all. So here's the starter XAML again.

<UserControl x:Class="SilverlightMouseEvents.MouseLeaveDemo"
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="White">
<
Ellipse x:Name="myEllipse" Fill="Blue" Width="150" Height="150" />
</
Grid>
</
UserControl>


This time I am going to do this all in the code-behind. I will add the event handlers when the application initializes. Here's my final C# for this example:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SilverlightMouseEvents
{
public partial class MouseLeaveDemo : UserControl
{
public MouseLeaveDemo()
{
InitializeComponent();
this.MouseLeave += new MouseEventHandler(MouseLeaveDemo_MouseLeave);
myEllipse.MouseLeave += new MouseEventHandler(myEllipse_MouseLeave);
}

void myEllipse_MouseLeave(object sender, MouseEventArgs e)
{
myEllipse.Fill = new SolidColorBrush(Colors.Purple);
}

void MouseLeaveDemo_MouseLeave(object sender, MouseEventArgs e)
{
myEllipse.Fill = new SolidColorBrush(Colors.Green);
}
}
}


MouseLeftButtonDown

For this event, I am going to continue to use the same XAML over and over. The only thing that changes is the reference to the class our XAML user control is using. I've shown how to rig up event handlers both in the XAML as well as in code. So, you've seen the XAML, I'm going to just show the code-behind for the next example here.

MouseLeftButtonDown is exactly like it looks. It fires when the user's left mouse button is pressed. Please note that I will be covering MouseLeftButtonUp next, and that there's a significant distinction between them. It's especially apparent when you start implementing Drag & Drop. Here's an example of adding MouseLeftButtonDown to our code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SilverlightMouseEvents
{
public partial class MouseLeftButtonDownDemo : UserControl
{
public MouseLeftButtonDownDemo()
{
InitializeComponent();
this.MouseLeftButtonDown += new MouseButtonEventHandler(MouseLeftButtonDownDemo_MouseLeftButtonDown);
myEllipse.MouseLeftButtonDown += new MouseButtonEventHandler(myEllipse_MouseLeftButtonDown);
}

void myEllipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
myEllipse.Fill = new SolidColorBrush(Colors.Green);
}

void MouseLeftButtonDownDemo_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
LayoutRoot.Background = new SolidColorBrush(Colors.Purple);
}
}
}


MouseLeftButtonUp

So far, we've created an event handler method for each individual event. There are many cases, however, where you want multiple items to be able to call the same method, so you're not writing the same code over and over. In this next example, I'm going to add a second circle, and have both of them change the background of the StackPanel they sit inside. Here's our new XAML file.

<UserControl x:Class="SilverlightMouseEvents.MouseLeftButtonUpDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<
StackPanel x:Name="LayoutRoot" Background="White" Orientation="Horizontal" HorizontalAlignment="Center" >
<
Ellipse x:Name="myEllipse" Fill="Blue" Width="150" Height="150" />
<
Ellipse x:Name="myEllipse" Fill="Red" Width="150" Height="150" />
</
StackPanel>
</
UserControl>


Now, we want each of the Ellipses, when the MouseLeftButtonUp event fires on them, to change the background of the ellipse that fired. Here's what the code looks like to do that.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SilverlightMouseEvents
{
public partial class MouseLeftButtonUpDemo : UserControl
{
public MouseLeftButtonUpDemo()
{
InitializeComponent();
myEllipse.MouseLeftButtonUp += new MouseButtonEventHandler(Ellipse_MouseLeftButtonUp);
myEllipse2.MouseLeftButtonUp += new MouseButtonEventHandler(Ellipse_MouseLeftButtonUp);
}

void Ellipse_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
Ellipse myCircle = sender as Ellipse;
myCircle.Fill = new SolidColorBrush(Colors.Orange);
}
}
}


You'll notice with this example that there's a second line of code in our event handler method. We have to grab a reference to the Ellipse that actually called the method. The "sender" parameter contains this information, so we have to grab that reference before assigning our new color.

MouseMove

In this final example, we are going to use the MouseMove event. Each time the mouse moves from its previous location, this event will fire. You can assign this to the entire control, or just a specific element of the application. In either case, you can do quite a few things with this, including drag and drop. We will cover that in a future post.

My XAML this time has two TextBoxes on the page. One named (cleverly) Xbox, and the other Ybox. We're going to insert the mouse's X and Y coordinates in these boxes as the user moves their mouse.

<UserControl x:Class="SilverlightMouseEvents.MouseMoveDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300" VerticalAlignment="Center">
<
StackPanel x:Name="LayoutRoot" Background="White">
<
TextBox x:Name="Xbox" Width="200" Height="35" Text="X" />
<
TextBox x:Name="Ybox" Width="200" Height="35" Text="Y"/>
</
StackPanel>
</
UserControl>


The code behind this probably doesn't look too complicated now, if you've followed this entire post, but we're using the MouseEventArgs this time, to determine where the mouse's current position is. We then simply assign those values to the text boxes.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SilverlightMouseEvents
{
public partial class MouseMoveDemo : UserControl
{
public MouseMoveDemo()
{
InitializeComponent();
this.MouseMove += new MouseEventHandler(MouseMoveDemo_MouseMove);
}

void MouseMoveDemo_MouseMove(object sender, MouseEventArgs e)
{
Xbox.Text = e.GetPosition(null).X.ToString();
Ybox.Text = e.GetPosition(null).Y.ToString();
}
}
}


Summary

This was a quick overview of the Mouse events that are available to you in Silverlight. Used together, you can create a pretty interactive environment for your user to use. In tomorrow's post, we are going to be covering screen transitions. Not only the ability to jump from one XAML file to the next, but also how to incorporate some Powerpoint-like transitions from one screen to the next.

kick it on DotNetKicks.com

Labels: , ,

posted by Jeff Blankenburg, 1:00 AM | link | 0 comments |

TUTORIAL: How To Create A SetTimeout Function In Silverlight

Monday, June 15, 2009

I am in the process of creating my first game in Silverlight, and one of the first things that I noticed I was missing from my Javascript-era toolkit was the setTimeout() function.

In short, this little function is the be-all, end-all of Javascript animation. It is the device you use to insert little "pauses" into your code so that objects appear to be moving. Without it, your pieces would simply start at one position, and appear at the final destination. I use it primarily to make sure that the browser takes the time to draw each step of the animation. Here's an example of me using the setTimeout() function in Javascript, circa 1999 (it's also less than 5K in total size!):



1. Create a new UIToolkit Class.

It was tempting when starting this tutorial to just create a class that does one thing. But as I move forward in my Silverlight adventures, it occurs to me that we're probably going to encounter more of these types of needs in the future. So, I'm creating a UIToolkit class in my project. This will contain all of the little helper functions I create going forwards.

public static class UIHelper
{

}

2. Inherit from System.Windows.Threading.DispatcherTimer

We are primarily going to be using the DispatcherTimer as is, but we also need it to accept an Action to execute when the timer expires. So we will be creating a new class that inherits from the standard DispatcherTimer, adding an Action to its definition.

public class ActionTimer: System.Windows.Threading.DispatcherTimer
{
public Action Action { get; set; }
}


3. Create a setTimeout method in UIToolkit

To keep it familiar for the Javascript folks out there, I'm keeping the name of the method setTimeout. It's not even my usual casing, but for this example, I'm going to stick with the Javascript syntax.

Inside this method, we're going to need an instance of our new ActionTimer, including the interval we want, and the method to call, as well as the calls to kick off the timer, and an event handler to manage each tick of the timer. Here's the code:

public static void setTimeout(int milliseconds, Action action)
{
var timer = new ActionTimer
{
Interval = new TimeSpan(0, 0, 0, 0, milliseconds),
Action = action
};
timer.Tick += new EventHandler(timer_Tick);
timer.Start();
}

static void timer_Tick(object sender, EventArgs e)
{
var t = sender as ActionTimer;
t.Stop();
t.Action();
t.Tick -= timer_Tick;
}


Or, just copy this into a new class file


public static class UIToolkit
{
public static void setTimeout(int milliseconds, Action action)
{
var timer = new ActionTimer
{
Interval = new TimeSpan(0, 0, 0, 0, milliseconds),
Action = action
};
timer.Tick += new EventHandler(timer_Tick);
timer.Start();
}

static void timer_Tick(object sender, EventArgs e)
{
var t = sender as ActionTimer;
t.Stop();
t.Action();
t.Tick -= timer_Tick;
}
}

public class ActionTimer : System.Windows.Threading.DispatcherTimer
{
public Action Action { get; set; }
}


4. How to call our new method

Now that we've got a setTimeout method that takes a number of milliseconds and an action, we need to call it for testing purposes. Below is the syntax we'll be using. The major difference you'll notice between this and the Javascript implementation is that our new method will take an entire block of code as our Action. In Javascript, we're forced to concatenate a string of commands together, and it can get pretty messy fast. We are setting this up to call our method every 1000 milliseconds, or every ONE second.

UIToolkit.setTimeout(1000, () =>
{
OurRecurringMethodCallShouldGoHere();
});


Let's see it in action!

Click here if the Silverlight below doesn't load. Click here to download this sample code.







Get Microsoft Silverlight



kick it on DotNetKicks.com

Labels: , , ,

posted by Jeff Blankenburg, 8:50 PM | link | 0 comments |

TUTORIAL: Creating an IE8 Accelator

Thursday, June 04, 2009

For those of you that have been using Internet Explorer 8 for a little while now, I'm hoping you've had a chance to customize your Accelerators. These are proving to be pretty valuable tools in my day-today surfing. Here's what my customized list looks like:



But one thing that has bothered me about these tools is that I didn't know how to make them. It probably wasn't hard, but it also wasn't obvious. That's the point of this post. I did some research, and it's actually a simple XML file on your web server, and some javascript in a button to reference it.

Of course, you need a service of some kind to actually provide value, but that's another thing. In my example, I'm going to create an Accelerator to post some text to Twitter.

1. Start with the default XML file.

If we visit the developer page for Accelerators, we are provided with the templates we can start with. I have bolded (and colored black) the values that we're going to need to change. You can read the entire spec on this document on MSDN.

<?xml version="1.0" encoding="UTF-8"?>
<
openServiceDescription xmlns="http://www.microsoft.com/schemas/openservicedescription/1.0">
<
homepageUrl>http://maps.live.com</homepageUrl>
<
display>
<
name>Map with Windows Live</name>
<
icon>http://www.live.com/favicon.ico</icon>
</
display>
<
activity category="map">
<
activityAction context="selection">
<
preview action= "http://maps.live.com/geotager.aspx">
<
parameter name="b" value="{selection}"/>
<
parameter name="clean" value="true"/>
<
parameter name="w" value="320"/>
<
parameter name="h" value="240"/>
</
preview>
<
execute action="http://maps.live.com/default.aspx">
<
parameter name="where1" value="{selection}" type="text" />
</
execute>
</
activityAction>
</
activity>
</
openServiceDescription>


2. Change the <homepageUrl> value.

At first, I thought this was a throwaway value, but it has to match the other values in the XML file or it won't work. I assume this is to prevent spoofing, though I think it would still be pretty easy to spoof a site. It has nothing to do with the Accelerator model, though. It's all about just creating a site that looks like the target site. I can discuss that in a later post though. So, since I'm working on an Accelerator for Twitter, my value for this will be http://twitter.com.

3. Change the <name>value.

This is the name that your users will see when they bring up the Accelerator Menu. In my case, I am going to make mine say "Tweet with Twitter."

4. Change the <icon> value.

If you want an icon to be displayed next to your text in the Accelerator menu, this is where you specify it. The Twitter icon seems appropriate for this, so my value is going to be the favicon from the Twitter site: http://twitter.com/favicon.ico.

5. Change the <category> value.

This is where your Accelerator will be categorized in the Accelerator menu. If it doesn't match an existing value EXACTLY, it will create another grouping. This includes capitalization, it seems. I'd like my entry to show up in a unique grouping, though, so I am using the value "Tweet."

6. Delete the <preview> section.

This is certainly not something you want to do every time, but unless you need to preview the results for the user (mapping and translation are good uses of this), we just want to take the user someplace. There's not much point in previewing it for them. So just delete that node.

7. Change the <action> value.

Inside the <execute> tag, we have an action value. This is the place that we will be directing the user when they click on our Accelerator in their menu. For Twitter, that place will be http://twitter.com/home. This gets the user to their Twitter home page, but we still need the ability to populate the "Tweet Box" on the page. Thankfully, Twitter and the Accelerator model can work together to accomplish this.

8. Change the <parameter> value.

You can have multiple parameter tags, and each one is ultimately treated like a query string variable to the URL that we specified in the previous step. Twitter accepts a parameter of "status" that, when used, will populate that text in the Twitter box. So, our name for our parameter will be status, and we will leave the value = {selection} because this will use the text the user highlighted to enter the Accelerator menu in the first place. So the entire use case for this process is this:

  • User highlights text.

  • User opens Accelerator menu.

  • User chooses our accelerator.

  • User is taken to Twitter, and the box is populated with the original highlighted text.

So here's what our final XML file looks like:

<?xml version="1.0" encoding="UTF-8"?>
<
openServiceDescription xmlns="http://www.microsoft.com/schemas/openservicedescription/1.0">
<
homepageUrl>http://twitter.com</homepageUrl>
<
display>
<
name>Tweet with Twitter</name>
<
icon>http://www.twitter.com/favicon.ico</icon>
</
display>
<
activity category="Tweet">
<
activityAction context="selection">
<
execute action="http://twitter.com/home/">
<
parameter name="status" value="{selection}" type="text" />
</
execute>
</
activityAction>
</
activity>
</
openServiceDescription>


9. Get that XML file on a web server.

I have placed my XML file here. It just needs to be publicly available.

10. Create a way for a user to install your Accelerator.

We just need to add a button or link on a web page for our users to click on. Here's some sample HTML you can use:

<button id="myButton" onclick="window.external.AddService('http://www.jeffblankenburg.com/twitteraccelerator/TwitterAccelerator.xml')">Tweet As Twitter</button>


And here's a sample button you can use to try it out!



kick it on DotNetKicks.com

Labels: , , ,

posted by Jeff Blankenburg, 8:32 AM | link | 0 comments |

Introducing the "Starter Series"

Tuesday, February 03, 2009

Many of my posts in the past have been tagged as a tutorial, where I walk you through each step you need to take in order to accomplish a specific goal. While popular, these posts tend to focus on advanced topics like WCF services and Silverlight development.

I have recognized, however, that many of the folks that read my blog don't get to use advanced technologies on a day-to-day basis. You are building websites or desktop applications, and just don't have the luxury of using the latest and greatest technologies.

This "Starter Series" is designed for you.

It will cover topics that can be used in everyday applications, and will be written in the context of a line-of-business application. We will work with things like a ListView control, AJAX controls, and other simple, but powerful approaches to software development. Since I am mostly a web developer, there will probably be a slant towards web development, but I will try to include posts on desktop application development as well.

My goal with this is to make you a more productive .NET developer.

If there are specific things you would like to see covered, I will be glad to take "requests." Just email me at starterseries@jeffblankenburg.com, or post a comment on this post. I'll get to ALL of them, I just can't promise how SOON.

Happy Coding!

You will be able to find all of the Starter Series posts here, as they are published.

Labels: ,

posted by Jeff Blankenburg, 11:09 AM | link | 1 comments |

TUTORIAL #11: Creating a Navigation In Silverlight

Thursday, January 15, 2009

A navigation is always a tricky project for every application. It seems to be in a constant state of flux, up until the minute the site goes live. With Silverlight, some of that becomes easier. This post will show you how to create a simple navigation in Silverlight.

Before I start through the steps, I want to point out that the navigation on my site is actually the ONLY part of my site done in Silverlight. The rest of the page is standard ASP.NET. I don't recommend creating your entire site in Silverlight, but rather, using it where it's appropriate: like a navigation. OK, having said that, here we go.

1. Create a new project in Visual Studio.

For many of you, this may seem remedial, but I want to make sure that I am documenting all of my steps. There's something frustrating to me about tutorials that assume you know the first few steps.

Create a new project in Visual Studio.

2. Add the web project it asks you about.

After you create a Silverlight project, Visual Studio will prompt you to create a Web Project to accompany it. Silverlight projects have to be hosted in a web page, so go ahead and create it.

Add the web project it asks you about.

3. Make your XAML document larger.

Open the Page.xaml file in your Silverlight project. By default, your UserControl tag is set to 400 x 300, though I don't know why that was the dimensions that were picked. IN our case, we're going to make our navigation 800 x 200. So your XAML should look like this now:

<UserControl x:Class="NavigationSample.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="800" Height="200">
<
Grid x:Name="LayoutRoot" Background="White">

</
Grid>
</
UserControl>

4. Open your solution in Expression Blend.

I would ALWAYS recommend using Expression Blend for any kind of Silverlight or WPF layout work, because you have the ability to drag and drop your shapes and colors. The next few steps will be shown in Blend.

The first thing I did was open my solution files in Blend.



5. Draw your navigation in Page.xaml.

I am going to be creating a nav similar to the one on my site at http://jeffblankenburg.com.



Before I create anything, I want to change the default Grid control to a Canvas. You can do this simply by changing the work "Grid" to the word "Canvas" in the XAML. Make sure to get the closing /Grid tag too. If you want to understand the differences, I have posts on Canvas, Grid, and StackPanel respectively.

Looking at it, the first thing I want to create is that silverish outer border. That's simply a rectangle with some rounded edges. I've also applied a gradient to it, so it looks a little metallic. Finally, I just made the StrokeThickness = 2. Here's how it looks in Blend (click to enlarge):



Also, here's how our entire XAML looks now:

<UserControl x:Class="NavigationSample.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="800" Height="200">
<
Canvas x:Name="LayoutRoot" Background="White">
<
Rectangle Width="780" Height="100" Stroke="#FF666666" RadiusY="15" RadiusX="15" StrokeThickness="2" Canvas.Top="50" Canvas.Left="11">
<
Rectangle.Fill>
<
LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<
GradientStop Color="#FFC4C4C4" Offset="1"/>
<
GradientStop Color="#FFFFFFFF" Offset="0"/>
</
LinearGradientBrush>
</
Rectangle.Fill>
</
Rectangle>
</
Canvas>
</
UserControl>

6. Create the background for the buttons.

There are probably many different ways to approach this problem, so we'll have to live with my simplified solution. Each button on the navigation is orange, with a subtle gradient. It was created the same way that we created the previous rectangle, so here's the XAML for it:

 <Rectangle Height="80" Width="760" RadiusY="7" RadiusX="7" StrokeThickness="2" Stroke="#FFB1B1B1" Canvas.Left="21" Canvas.Top="60">
<
Rectangle.Fill>
<
LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<
GradientStop Color="#FFF7D599" Offset="1"/>
<
GradientStop Color="#FFE8AF34"/>
</
LinearGradientBrush>
</
Rectangle.Fill>
</
Rectangle>
All we need to do is take that XAML, and place it immediately after the rectangle we've already got there. Here's what your design view should look like now:



7. Position your TextBlocks.

We've now reached the step for why I wanted to be using a Canvas as our outer container. We're going to position each of our text elements, and we're looking for pixel by pixel accuracy. The Canvas provides us that.

One of the other things you'll notice about my navigation is that I am not using one of the standard 8 fonts that come with Silverlight. Thankfully, I've written a post on embedding fonts in Silverlight as well. Make sure you read that if you want something different than Arial, Times New Roman, or Courier. If you use Comic Sans, call me so I can smack you. :)

Anyways, I have 6 navigation elements that I want to create. I am simply using TextBlock controls to show text...they're not actually going to do anything. They just have to look pretty. All I did was create the first one, copy it 5 times, and drag each one to their positions. You should notice that Blend provides some nice guides for alignment purposes. It makes life easy. Here's how I have laid them out:



And here's the XAML document in its entirety, thus far:

<UserControl x:Class="NavigationSample.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="800" Height="200">
<
Canvas x:Name="LayoutRoot" Background="White">
<
Rectangle Width="780" Height="100" Stroke="#FF666666" RadiusY="15" RadiusX="15" StrokeThickness="2" Canvas.Top="50" Canvas.Left="11">
<
Rectangle.Fill>
<
LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<
GradientStop Color="#FFC4C4C4" Offset="1"/>
<
GradientStop Color="#FFFFFFFF" Offset="0"/>
</
LinearGradientBrush>
</
Rectangle.Fill>
</
Rectangle>
<
Rectangle Height="80" Width="760" RadiusY="7" RadiusX="7" StrokeThickness="2" Stroke="#FFB1B1B1" Canvas.Left="21" Canvas.Top="60">
<
Rectangle.Fill>
<
LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<
GradientStop Color="#FFF7D599" Offset="1"/>
<
GradientStop Color="#FFE8AF34"/>
</
LinearGradientBrush>
</
Rectangle.Fill>
</
Rectangle>
<
TextBlock Text="Home" FontFamily="ROCK.TTF#Rockwell" FontSize="20" Canvas.Top="91" Canvas.Left="49" Foreground="#FF6D6D6D" FontWeight="Normal"/>
<
TextBlock Text="Archive" FontFamily="ROCK.TTF#Rockwell" FontSize="20" Canvas.Top="91" Canvas.Left="168" Foreground="#FF6D6D6D" FontWeight="Normal"/>
<
TextBlock Text="About" FontFamily="ROCK.TTF#Rockwell" FontSize="20" Canvas.Top="91" Canvas.Left="312" Foreground="#FF6D6D6D" FontWeight="Normal"/>
<
TextBlock Text="Code" FontFamily="ROCK.TTF#Rockwell" FontSize="20" Canvas.Top="91" Canvas.Left="443" Foreground="#FF6D6D6D" FontWeight="Normal"/>
<
TextBlock Text="Slides" FontFamily="ROCK.TTF#Rockwell" FontSize="20" Canvas.Top="91" Canvas.Left="570" Foreground="#FF6D6D6D" FontWeight="Normal"/>
<
TextBlock Text="Contact" FontFamily="ROCK.TTF#Rockwell" FontSize="20" Canvas.Top="91" Canvas.Left="684" Foreground="#FF6D6D6D" FontWeight="Normal"/>
</
Canvas>
</
UserControl>

8. We need to make the buttons change color.

Before, I said that the TextBlocks don't actually do anything, and that's true. What I am going to do instead is cover each of those TextBlocks with a semi-transparent Rectangle, and that's the XAML element that is going to do all of the work. I'm also going to add the vertical gray seperators between each TextBlock, but those are just Rectangles. Nothing very exciting. You'll see it in the XAML. Here's my rectangles:

 <Rectangle Height="76" Width="109" Opacity="0" Fill="#FFFFFFFF" Stroke="{x:Null}" Canvas.Left="23" Canvas.Top="62" x:Name="Home"/>
<
Rectangle Height="76" Width="139" Opacity="0" Fill="#FFFFFFFF" Stroke="{x:Null}" Canvas.Left="133" Canvas.Top="62" x:Name="Archive"/>
<
Rectangle Height="76" Width="132" Opacity="0" Fill="#FFFFFFFF" Stroke="{x:Null}" Canvas.Left="273" Canvas.Top="62" x:Name="About"/>
<
Rectangle Height="76" Width="126" Opacity="0" Fill="#FFFFFFFF" Stroke="{x:Null}" Canvas.Left="406" Canvas.Top="62" x:Name="Code"/>
<
Rectangle Height="76" Width="122" Opacity="0" Fill="#FFFFFFFF" Stroke="{x:Null}" Canvas.Left="533" Canvas.Top="62" x:Name="Slides"/>
<
Rectangle Height="76" Width="122" Opacity="0" Fill="#FFFFFFFF" Stroke="{x:Null}" Canvas.Left="656" Canvas.Top="62" x:Name="Contact"/>

There are two things special about these rectangles. The first is that I have actually named them. Each one has an x:Name property, with an indication of which TextBlock it is covering. The second thing you should notice is that they have an opacity set to ZERO. This means that they are completely transparent. An opacity of 1 means that you can't see through them at all. This is the property we are going to manipulate with some code. Here's what the nav looks like now, and the XAML will follow it.



<UserControl x:Class="NavigationSample.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="800" Height="200">
<
Canvas x:Name="LayoutRoot" Background="White">
<
Rectangle Width="780" Height="100" Stroke="#FF666666" RadiusY="15" RadiusX="15" StrokeThickness="2" Canvas.Top="50" Canvas.Left="11">
<
Rectangle.Fill>
<
LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<
GradientStop Color="#FFC4C4C4" Offset="1"/>
<
GradientStop Color="#FFFFFFFF" Offset="0"/>
</
LinearGradientBrush>
</
Rectangle.Fill>
</
Rectangle>
<
Rectangle Height="80" Width="760" RadiusY="7" RadiusX="7" StrokeThickness="2" Stroke="#FFB1B1B1" Canvas.Left="21" Canvas.Top="60">
<
Rectangle.Fill>
<
LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<
GradientStop Color="#FFF7D599" Offset="1"/>
<
GradientStop Color="#FFE8AF34"/>
</
LinearGradientBrush>
</
Rectangle.Fill>
</
Rectangle>
<
TextBlock Text="Home" FontFamily="ROCK.TTF#Rockwell" FontSize="20" Canvas.Top="91" Canvas.Left="49" Foreground="#FF6D6D6D" FontWeight="Normal"/>
<
TextBlock Text="Archive" FontFamily="ROCK.TTF#Rockwell" FontSize="20" Canvas.Top="91" Canvas.Left="168" Foreground="#FF6D6D6D" FontWeight="Normal"/>
<
TextBlock Text="About" FontFamily="ROCK.TTF#Rockwell" FontSize="20" Canvas.Top="91" Canvas.Left="312" Foreground="#FF6D6D6D" FontWeight="Normal"/>
<
TextBlock Text="Code" FontFamily="ROCK.TTF#Rockwell" FontSize="20" Canvas.Top="91" Canvas.Left="443" Foreground="#FF6D6D6D" FontWeight="Normal"/>
<
TextBlock Text="Slides" FontFamily="ROCK.TTF#Rockwell" FontSize="20" Canvas.Top="91" Canvas.Left="570" Foreground="#FF6D6D6D" FontWeight="Normal"/>
<
TextBlock Text="Contact" FontFamily="ROCK.TTF#Rockwell" FontSize="20" Canvas.Top="91" Canvas.Left="684" Foreground="#FF6D6D6D" FontWeight="Normal"/>

<
Rectangle Height="77" Width="1" Fill="#FFB1B1B1" Stroke="{x:Null}" Canvas.Top="62" Canvas.Left="132" x:Name="Divider1"/>
<
Rectangle Height="77" Width="1" Fill="#FFB1B1B1" Stroke="{x:Null}" Canvas.Top="62" Canvas.Left="272" x:Name="Divider2"/>
<
Rectangle Height="77" Width="1" Fill="#FFB1B1B1" Stroke="{x:Null}" Canvas.Top="62" Canvas.Left="405" x:Name="Divider3"/>
<
Rectangle Height="77" Width="1" Fill="#FFB1B1B1" Stroke="{x:Null}" Canvas.Top="62" Canvas.Left="532" x:Name="Divider4"/>
<
Rectangle Height="77" Width="1" Fill="#FFB1B1B1" Stroke="{x:Null}" Canvas.Top="62" Canvas.Left="655" x:Name="Divider5"/>
<
Rectangle Height="76" Width="109" Opacity="0" Fill="#FFFFFFFF" Stroke="{x:Null}" Canvas.Left="23" Canvas.Top="62" x:Name="Home" MouseEnter="MouseOver" MouseLeave="MouseOut" MouseLeftButtonDown="MouseClick" />
<
Rectangle Height="76" Width="139" Opacity="0" Fill="#FFFFFFFF" Stroke="{x:Null}" Canvas.Left="133" Canvas.Top="62" x:Name="Archive" MouseEnter="MouseOver" MouseLeave="MouseOut" MouseLeftButtonDown="MouseClick" />
<
Rectangle Height="76" Width="132" Opacity="0" Fill="#FFFFFFFF" Stroke="{x:Null}" Canvas.Left="273" Canvas.Top="62" x:Name="About" MouseEnter="MouseOver" MouseLeave="MouseOut" MouseLeftButtonDown="MouseClick" />
<
Rectangle Height="76" Width="126" Opacity="0" Fill="#FFFFFFFF" Stroke="{x:Null}" Canvas.Left="406" Canvas.Top="62" x:Name="Code" MouseEnter="MouseOver" MouseLeave="MouseOut" MouseLeftButtonDown="MouseClick" />
<
Rectangle Height="76" Width="122" Opacity="0" Fill="#FFFFFFFF" Stroke="{x:Null}" Canvas.Left="533" Canvas.Top="62" x:Name="Slides" MouseEnter="MouseOver" MouseLeave="MouseOut" MouseLeftButtonDown="MouseClick" />
<
Rectangle Height="76" Width="122" Opacity="0" Fill="#FFFFFFFF" Stroke="{x:Null}" Canvas.Left="656" Canvas.Top="62" x:Name="Contact" MouseEnter="MouseOver" MouseLeave="MouseOut" MouseLeftButtonDown="MouseClick" />
</
Canvas>
</
UserControl>


9. We need some event handlers.

Each of the Rectangles that we just created need event handlers so that we can do things when the user rolls over them, as well as clicks on them. All we need to add to each of those 6 Rectangles is this code:

MouseEnter="MouseOver" MouseLeave="MouseOut" MouseLeftButtonDown="MouseClick"

I actually already added them for you in the XAML from step #8, but I want to make sure you know why they are there. We're going to define the methods in our next step.

10. Let's write some event handler methods!

So our XAML is technically done. If our designer wanted to change stuff later, he/she can do whatever he/she wants. We just need to write some methods in the Page.xaml code-behind file, and we're done with this little project.

Before we do that, however, I've got one small task for you. In order to do this efficiently, we're going to need to add a reference to this Silverlight project. We're adding System.Net. To add a reference, just right click on the "References" folder in your project, and choose "Add Reference..." In the box that appears, just choose System.Net, and click "OK."



The reason we're doing this is so that we have access to the HtmlWindow and HtmlPage classes. We'll be using those in a method to redirect our user to another page.

Our MouseOver and MouseOut methods are very similar. One is going to add some opacity to our Rectangles, and the other will remove it again. This will give us a very nice rollover effect when the user's mouse moves over each nav element. Here's what those methods look like:

 private void MouseOver(object sender, MouseEventArgs e)
{
Rectangle activebox = sender as Rectangle;
activebox.Opacity = .2;
}

private void MouseOut(object sender, MouseEventArgs e)
{
Rectangle activebox = sender as Rectangle;
activebox.Opacity = 0;
}


Our (kinda) final method is the one to handle clicking on the nav. Ideally, when a user clicks on a nav element, they expect to be whisked away to a new page. And that's the experience we are going to provide them. Here's the method:

 private void MouseClick(object sender, MouseButtonEventArgs e)
{
Rectangle activebox = sender as Rectangle;
if (activebox != null)
{
switch (activebox.Name.ToString().ToUpper())
{
case "HOME":
LaunchNewPage("http://jeffblankenburg.com/default.aspx");
break;
case "ARCHIVE":
LaunchNewPage("http://jeffblankenburg.com/archive.aspx");
break;
case "ABOUT":
LaunchNewPage("http://jeffblankenburg.com/aboutjeffblankenburg.aspx");
break;
case "CODE":
LaunchNewPage("http://jeffblankenburg.com/code.aspx");
break;
case "SLIDES":
LaunchNewPage("http://jeffblankenburg.com/slides.aspx");
break;
case "CONTACT":
LaunchNewPage("http://jeffblankenburg.com/contact.aspx");
break;
}
}
}

private void LaunchNewPage(string URI)
{
{
HtmlWindow window = HtmlPage.Window;
Uri uri = new Uri(URI);
window.Navigate(uri);
}
}


You'll see that the cases in the switch statement should exactly match the names of the 6 Rectangles that we are using, but capitalized. Since I'm never certain exactly which way I capitalized my names, I find it easier just to compare those names converted to all capital letters. That's what the .ToUpper() is for in the switch statement.

You should also see that we call a method named "LaunchNewPage()" in each case. I have extracted the page redirect into its own function. The reason for this, at least initially, was because I wasn't sure if I wanted to open new windows for each click, or if I just wanted to redirect the user in the same browser window. By extracting this functionality, I can easily change it later for all of them, without having to touch each individual case. I do this for things like alert() in javascript as well. That way, if later, I want to make those alert boxes something nicer, like a popup DIV or even another window, I can do it easily.

So there you go! We've got a working navigation!

Click here to see the Silverlight Navigation working...

Click here to get the source code for this entire solution...

kick it on DotNetKicks.com

Labels: , , , , , , ,

posted by Jeff Blankenburg, 9:46 AM | link | 5 comments |

TUTORIAL #10: Running a PowerPoint Slideshow From Your Windows Mobile Phone

Wednesday, November 19, 2008

During the recent .NET University, I had my first iPhone envy. Leon Gersing was giving a presentation on the basics of OOP (which was excellent), and I noticed that he was carrying around his iPhone while he talked.

On closer inspection, he was actually using his iPhone as his presentation clicker. He was able to move forward and backward in his presentation, and his phone was actually displaying his speaker notes in his hand! How cool is that?

Frustrated, I was convinced that there must be a way to do this on a Windows Mobile phone. I have given plenty of presentations that sing the praises of my WM6 phone, and have even compiled a list of the things I have used it for in a specific week.



So, you'll notice that "Run a Powerpoint presentation" is not on my list. But today, I have to edit that slide. Here's how you can do it too:

1) Download Windows SideShow for Windows Mobile

Get the files here. This is the first piece of all of this. Windows SideShow is a new technology that delivers information from your PC to a secondary display on two kinds of devices: those that are integrated into a computer, such as a small color display in a laptop lid; and those that are separate from a computer, such as a remote control or mobile phone. With this additional display you can view important information whether your laptop is on, off, or in sleep mode.

2) Install the .CAB file on your phone.

There is an excellent help file in the files you just downloaded, and I will leave it to you to make sure that you get this software installed on your phone. If you're still running Windows Mobile 5, make sure that you get the .NET Compact Framework installed on your phone as well (the installer is also included, for your convenience.)

3) Create a Bluetooth connection to your phone from your Vista PC.

Yes, if I didn't mention it, SideShow is a feature of Windows Vista. This will not work in Windows XP. My apologies. To create the Bluetooth connection, here's the steps:
  1. On your PC, go to Control Panel > Hardware and Sound > Bluetooth devices > Set up a Bluetooth enabled device
  2. On your phone, open your Start menu, choose Bluetooth, and then choose Bluetooth Manager.
  3. Make sure the status is set to "Bluetooth ON", that you have a name for your device that you like (mine is blankenq for my Motorola Q9c), and that the checkbox reading "Allow other Bluetooth devices to see this phone" is checked.
  4. Back on your PC, click the "Add..." button on the Devices tab.
  5. Check the box that reads "My device is set up and ready to be found.", and click Next.
  6. It will search for available Bluetooth devices, and eventually show you a list. Choose the device that has the name you used when you set up your phone, and click Next.
  7. Next, it will ask you "Do you need a passkey to access your device?" The answer is YES. Yes, you do. I prefer using the choice: "Let me choose my own passkey." Then enter a passkey from 8-16 digits long. Remember what you typed, and then click Next.
  8. Look at your phone. It should now be asking you to enter that passkey again. Enter it in the box, and click Accept.
  9. Your PC will then install some device drivers, and you're off and running. Your phone is now paired with your PC!
  10. Click Finish, and you can exit your way though the rest of the Control Panel.

4) Install the Office PowerPoint Remote Gadget

Get the files here.This is the actual "gadget" that you can run in Windows SideShow. This is what you use to manipulate your Powerpoint presentations. To make your life easy, check the box that reads, "Open Windows SideShow in Control Panel when I click Finish." If you forget the box, open the Control Panel, and choose Programs > Windows SideShow. In here, you should see 4 boxes available for checking. Your email, your calendar, Powerpoint, and Windows Media Player. The three that aren't Powerpoint come with SideShow by default. This will allow you to see your email, view your calendar, control Windows Media Player, and run Powerpoint presentations from your PC, even if it is sleeping. Cool, huh? Check the boxes you want access to.

5) Take a look at your Home screen on your phone.

You should now see a new item in your Home screen. This is the Windows SideShow section, and it is how you get to the applications available to you in Windows SideShow. Fire up a PowerPoint presentation on your PC, and it will show up in the PowerPoint remote menu. You can start the slideshow, move from one slide to the next, and the speaker notes for each slide are even shown on your phone's screen!

Eat that, Mr. Gersing. :)

kick it on DotNetKicks.com

Labels: , , , , ,

posted by Jeff Blankenburg, 4:42 PM | link | 5 comments |

TUTORIAL #9: Embedding Fonts In Silverlight 2

Monday, November 10, 2008

Many times when I am creating a Silverlight application, I'm not happy using the default 10 fonts that are part of Silverlight. I've got hundreds of other fonts on my machine that make more sense, but then I need that font on every user's machine that visits my site. Thankfully, Silverlight makes that easy for me.

1) Add a TextBlock to your XAML.


<TextBlock Width="100" Height="100" Text="Jeff Blankenburg"></TextBlock>

2) Add your font to the project.

In Expression Blend and in Visual Studio, this is pretty easy. Right click on your Silverlight project, and choose "Add Existing Item..." From there navigate to your Fonts folder (or where ever you're keeping fonts these days), which in Windows Vista is found at c:\windows\fonts\. Choose the TrueType font you wish to use (that's any font file with a .TTF extension), and add it to your project.

3) Understand what we're actually doing.

In Visual Studio, click on your new font file in your project. In the properties window, one of the items in the list is "Build Action." Make sure that this is set to "Resource." It should be set to that by default, but confirming it never hurts. What we're doing is telling the application that this is a resource that we will need access to when the application runs. Since Silverlight applications run on the client machine, it will be packed inside your .XAP file for the trip across the Internet.

4) Apply your font to your textblock.

You may have noticed, if you were working ahead, that applying a font to your textblock is simple. In Studio, you can just type in the property FontFamily for the TextBlock, and specify the font you want to use. However, the preview window will only respond for the 10 fonts that are native to Silverlight. These are: Arial, Comic Sans, Courier New, Georgia, Lucida Sans Unicode, Portable User Interface, Times New Roman, Trebuchet MS, Verdana, and Webdings.
<TextBlock Width="100" Height="100" Text="Jeff Blankenburg" FontFamily="Times New Roman"></TextBlock>
In Expression Blend, you get a nice dropdown to choose your fonts from. They even have a nice icon system to show you which fonts are actually available. The default fonts have an A with the Silverlight logo next to them, and the new font we have added has an application icon with an A over it. Fonts without an icon need to be included (using this process) before they can be used. You CAN use them, but that font will not be shown on any machine that does not have that font installed.



Here's the tricky part of using a foreign font. We don't just get to reference the name of this font. There's a unique syntax for making sure we get this correct. A font actually has two names: the name of the .ttf file, and the actual name of the font. We will need to know both of these. In my example, I am using the font "Calibri." So in order to use that font, I need my FontFamily property to look like the following line:

<TextBlock Width="100" Height="100" Text="Jeff Blankenburg" FontFamily="calibri.ttf#Calibri"></TextBlock>


What I have done is tell Silverlight that I want my font to come from the file named calibri.ttf, and I want the font from that file named Calibri.

That's all it takes! You should now be able to see that font rendered in the Visual Studio preview pane, as well as Expression Blend and our running application. Just remember that we need to package these external fonts into our application, and then we have to use this alternate syntax to point directly to the font.

I hope this helps you get past the hurdle of using the same 10 fonts over and over and over. Please let me know how this helps you!

kick it on DotNetKicks.com

Labels: , , , , ,

posted by Jeff Blankenburg, 2:23 PM | link | 2 comments |

TUTORIAL #8: Creating An AutoComplete TextBox With AJAX

Monday, October 27, 2008

There's this incredible resource in the AJAX Control Toolkit, and it's about time we started using it. Today I am going to talk about the AutoComplete Extender, and how simple it is to rig up to an existing ASMX web service. As usual, I will provide the code at the end of this post in both C# and VB.NET. Let's start at the beginning:

1) Create a new web site.



2) Create a new ASMX web service.

Right-click on the project, and choose "Add New Item..." From the dialog box, choose Web Service, and name the service NCAA.asmx (I'll explain the name later.) Also, for our demo, we're going to leave the code in one single file. Uncheck the "Place code in a seperate file" box.


3) Write a quick web method.

We'll be making this more complicated later, but for now, we're going to write a simple web service that is meant for the AutoComplete Extender. For this control, our method must have this signature:
public string[] GetTeamList(string text)
So for now, here's the full code to put inside your ASMX file:
using System;
using System.Collections;
using System.Configuration;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml.Linq;


namespace AutoComplete
{
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class ncaa : System.Web.Services.WebService
{
[WebMethod]
public string[] getTeamList(string prefixText)
{
string[] teamName = new String[6];
teamName[0] = "Bowling Green State University";
teamName[1] = "Ohio State University";
teamName[2] = "Ohio University";
teamName[3] = "Cleveland State University";
teamName[4] = "University of Cincinnati";
teamName[5] = "University of Dayton";
return teamName;
}
}
}


4) We should verify our web service works.

Right click on your ASMX file, and choose "View in Browser." Clicking on the method name, GetTeamList, will ask you for a "prefixText" value. That value isn't used yet, so just click the Invoke button to see our list of colleges returned in XML.


5) Now we need add a textbox.

We're actually going to add a few things to our Default.aspx page, but the first thing to do is add a standard TextBox control to the page. You should be able to grab that from your toolbox. The other things to add require a potential download first. I'll show you the completed HTML after step #9.


6) Get the ASP.NET AJAX Library.

You only need to do this if you're not using the ASP.NET 3.5 framework. Here is the link to the AJAX library downloads.


7) Get the AJAX Control Toolkit.

The control toolkit is an open source project on CodePlex, and you can download it here. Unless you're really interested in contributing/taking it apart, all you really need is the link to the DLL Only. Save that to your computer, and then you need to add it to your Toolbox.


8) Add it to your VS Toolbox.

Here's the quick way to get those new controls and extenders into your Visual Studio toolbox:
  1. Pin out your toolbox by clicking on the pushpin icon at the top.
  2. Right-click on the toolbox and choose "Add Tab"
  3. Give it a name like "AJAX Control Toolkit."
  4. Drag the toolkit .DLL file from your computer to the new tab you created.
  5. You should now see your new controls in your toolbox.


9) Add our AJAX elements to the page.

Now we need to add an AJAX ScriptManager and a new AutoCompleteExtender to our page. You can either type them, or just drag them from your toolbox. Here's what your Default.aspx file should look now:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="AutoComplete._Default" %>
<%
@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="cc1" %>

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

<
html xmlns="http://www.w3.org/1999/xhtml" >
<
head runat="server">
<
title>Jeff Blankenburg | AutoCompleteExtender</title>
<
link href="style.css" rel="stylesheet" type="text/css" />
</
head>
<
body>
<
form id="form1" runat="server">
<
div>
<
asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
<
asp:TextBox ID="collegeteam" runat="server"></asp:TextBox>
<
cc1:AutoCompleteExtender ID="collegeteamextender" runat="server" ServicePath="ncaa.asmx" ServiceMethod="getTeamList" MinimumPrefixLength="3" CompletionSetCount="10" TargetControlID="collegeteam">
</
cc1:AutoCompleteExtender>
</
div>
</
form>
</
body>
</
html>


10) Some explanation for the HTML...

You'll notice that I added some properties to the controls that are on our page, so let me explain what they are.
  • Service Path - this is the web service that we are going to call
  • Service Method - this is the method in that web service that we are calling.
  • Minimum Prefix Length - this is the number of characters a user must enter before the extender will start calling the web service. If you've got thousands or millions of possible return values, I'd make this 3 or 4, at a minimum.
  • Completion Set Count - this forces the control to only show a specific number of results (you need to modify your web service for this to work).


11) Run the web site.

At this point, we should have a fully functional AutoComplete extender. You can run the site to check it out. Just start typing in the textbox to see what happens. But we're pulling back a static list of data. That's not very interesting at all. I want to do something realistic with this functionality.

12) Web Service += Usefulness

The reason that I called my web service NCAA is because I want to allow my users to choose from a list of colleges as they are typing. The first thing we'll need then, is a database of colleges. Here's my database of all of the Division I schools, with their names, mascots, and hex colors. Now we need to modify our web service so that we're pulling results out of the database based on our text typed in the TextBox. Here's my new web service code (you can just copy and paste over the old stuff.)

using System;
using System.Collections;
using System.Configuration;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml.Linq;


namespace AutoComplete
{
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class ncaa : System.Web.Services.WebService
{
[WebMethod]
public string[] getTeamList(string prefixText)
{
DataSet teams = new DataSet();
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);
string sql = "SELECT team_name FROM team WHERE team_name LIKE '" + prefixText + "%'";
SqlCommand sqlCmd = new SqlCommand(sql, conn);
conn.Open();
SqlDataAdapter sqlAdpt = new SqlDataAdapter();
sqlAdpt.SelectCommand = sqlCmd;
sqlAdpt.Fill(teams);
string[] teamName = new String[teams.Tables[0].Rows.Count];
int i = 0;
try
{
foreach (DataRow row in teams.Tables[0].Rows)
{
teamName.SetValue(row["team_name"].ToString(), i);
i++;
}
}
catch { }
finally
{
conn.Close();
}
return teamName;
}
}
}


You'll notice that without modifying our .aspx file, we can completely update the functionality behind our web service. This seperation can be invaluable when building applications from web services, because you don't want a change in one thing to potentially break another.

13) What about that CompletionSetCount?

So I mentioned earlier that you can set the number of results you want returned so that you don't end up with a huge, unmanageable list. This will require a small change to your web service, but nothing significant. Without these changes, your CompletionSetCount value will just be ignored. The first change is that we need to receive a second parameter (an integer) in our WebMethod. That's right, the extender just sends it as a second parameter to your method. The second change, then, is just to modify your method to utilize that value. Here's my final web service source code, using this added feature:

using System;
using System.Collections;
using System.Configuration;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml.Linq;


namespace AutoComplete
{
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class ncaa : System.Web.Services.WebService
{
[WebMethod]
public string[] getTeamList(string prefixText, int count)
{
DataSet teams = new DataSet();
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);
string sql = "SELECT TOP " + count + " team_name FROM team WHERE team_name LIKE '" + prefixText + "%'";
SqlCommand sqlCmd = new SqlCommand(sql, conn);
conn.Open();
SqlDataAdapter sqlAdpt = new SqlDataAdapter();
sqlAdpt.SelectCommand = sqlCmd;
sqlAdpt.Fill(teams);
string[] teamName = new String[teams.Tables[0].Rows.Count];
int i = 0;
try
{
foreach (DataRow row in teams.Tables[0].Rows)
{
teamName.SetValue(row["team_name"].ToString(), i);
i++;
}
}
catch { }
finally
{
conn.Close();
}
return teamName;
}
}
}


Demo

Here's a link to the active demo. Because my hosting provider does not support SQL Express (we can talk about CrystalTech later), I am actually running it from a full SQL 2005 database, but the MDB I provided is merely a copy of the table I am using.

Click to see the AutoComplete demo.

Source Code

Click to download the AutoComplete demo in C#. Click to download the AutoComplete demo in VB.NET.

kick it on DotNetKicks.com

Labels: , , , , ,

posted by Jeff Blankenburg, 12:16 PM | link | 10 comments |

Blankenthoughts: A Popular History Tour

Wednesday, October 22, 2008

Inspired by the most recent post over at Advergirl (a friend of mine), I have decided to list out links to the 10 most popular posts from the entire 2+ year history of my blog. The reason for this is to introduce some of my older (but still useful) articles to some of my newer readers. So here goes:

10) Calling Javascript From Silverlight 2

This is another in my series of tutorial posts, which walks you through creating a Silverlight application that can both call, pass values to, and retrieve values from a Javascript method in the web page host. An invaluable read for any Silverlight developer.

9) Extraordinary Nut Snack

This is a commentary on the commercials from Frito-Lay on their new line of snacks. It includes a video of their first try at commercials. Beautifully done in CGI, the almonds fall like dominoes. And then they say the title of this post. Your mind will wander.

8) CAPTCHA the Flag

This is a complete walkthrough on implementing Asirra, a new CAPTCHA control (of sorts) from Microsoft Research. It's incredibly easy to add to your application, and might even result in an adoption!

7) 6 Tips For Making Website Registration User Friendly

There are a million different websites out there, and there's a million different ways to register for an account on them. This is a list of simple suggestions for the next time you head down the "registration" path. Best tip? Make it easier for your users, not for the developer building the pages.

6) Top 10 Things New Twitter Users Need To Know To Get Followers

You only get one real chance to impress upon someone why they should follow you on Twitter. Following these rules will help you immensely.

5) Simple Resizing In Silverlight

One of the beauties of Silverlight is that it is based on vector graphics. This means that no matter what size you display them, they don't get pixelated and blurry. Vector graphics can grow or shrink to any size, and this tutorial shows you the simple way to make it happen.

4) Creating A Simple Silverlight Animation

As the creator of the CodeMash logo, I was excited when I found out I could convert my Adobe Illustrator file to XAML. Once that was completed, the next logical step was to animate the gears. This tutorial shows you how to do that, as well as a quick tour around Expression Blend.

4) Left Outer Join In LINQ

As someone who has a hard time getting out of a traditional SQL mindset, when I started using LINQ, the question of how to emulate a left outer join immediately confronted me. This outlines the simple way to do just that.

3) I Hate Windows, I'm Moving To Windows Mojave

This was briefly written to announce the Windows Mojave website and advertising campaign. It has certainly has its praises and criticims, but this post got more traffic in one day than any other post has ever gotten.

2) TUTORIAL: Creating a WCF Service for Silverlight 2 and SQL

One of my first "tutorial" posts, this hit the ground running, and hasn't looked back. It's an excellent beginning example of how to get Silverlight talking to a web service that accesses a SQL database.

1) General Ionics: Fake or Fab?

This article was written while I was buying a water filtration system for my home. While not technical in nature, this has been, by far, my most popular post to date.

Labels: , , , ,

posted by Jeff Blankenburg, 8:35 PM | link | 0 comments |

TUTORIAL #7: Downloading Videos From YouTube

Wednesday, October 08, 2008


I've done a ton of presentations over the years. Sometimes there's a video on YouTube or some other streaming video site that would complement my presentation. (Like this one.) But many places that I present at don't have Internet access readily available. So those videos go unplayed, and my presentation just doesn't have the pizazz I was hoping for.

I have finally found a way to get those videos, in any format I want, thanks to a few tools. Now I can save those videos to my Zune/iPod/other device. Now I can embed those videos right inside my Powerpoint presentations. Here's how I do it:

1) Find a video you want to download.

Just cpoy the URL of the page the video is shown on. I'm going to use this one as my example. It's an interpretation of Daft Punk's "Harder Better Faster Stronger." The person in the video wrote the lyrics to the song (there's only like 12 words, over and over) on their hands, and shows those words at the appropriate times. Highly entertaining, I promise.

2) Download that video.

Here's the first tool we need to use. Open a new browser window and go to http://www.savevid.com. Near the top of the page is a textbox for you to paste your URL into. Do that, and then click the download button. After a few seconds (or minutes, depending on the length of your video), it will present you with a few links. One of those links is to "Download MP4." Do this, and save the file to your hard drive.

3) That's IT? No, there's more.

That's only half the task. MP4 files can be added to your media player of choice, but they're not used many other places. What if my device doesn't support MP4, or I want to embed this file in a presentation? There's gotta be a simple way to convert this video to another format. And there is.

4) Get Expression Media Encoder 2.

This was the first time I had used Expression Encoder, but it is SUPER easy. Download it here. During the install, it will ask you if you want to install Quicktime too. YES. Yes you do. You need it to work with MP4 files. (Thanks Apple, for your wall.)

5) Import your new MP4 file.

Once you've got Expression Media Encoder installed, open it up, and from the File menu, choose Import. Choose your MP4 file from earlier, and open it up. By default, all of the settings are preset to create a high-res WMV file.

6) Export your new WMV file.

All you need to do now is go back up to the File menu and choose "Encode." It will create a new WMV file for you that can be used in just about every application that uses video on Windows. (If you're on a Mac, that MP4 file should be the one you use.) Voila! You've downloaded a movie from YouTube, and now you can do anything you want with it!

kick it on DotNetKicks.com

Labels: , , , , ,

posted by Jeff Blankenburg, 4:23 PM | link | 4 comments |

TUTORIAL #6: Visual Studio Code Highlighting To HTML

Tuesday, October 07, 2008


Many times when I'm writing a blog post, I want to include some of the source code from the project I am talking about. For most people, seeing the syntax highlighted the way it is in Visual Studio makes it the most readable. I've tried it manually, and it's very hard to do. (At least to do quickly.)

Then I discovered that there was a plug-in for Live Writer (actually, there's like 6.) But Live Writer has some quirks working with my blogging engine, so I really struggled with it (even though the code looked awesome!)

Today I almost just sat down and wrote my own converter, that would take source code from Visual Studio, and translate it into CSS styles. But I figured one more trip around the web couldn't hurt, so I headed to my favorite search engine and started hunting. The very first entry was exactly what I was looking for.

A guy named Douglas Stockwell has created a tiny little executable that interacts with your clipboard in Windows. He actually created one of the Live Writer plug-ins as well. The basics of the application he wrote is this. Copy some source code to your clipboard (Ctrl + C), run this executable, and then paste (Ctrl + V) your newly formatted HTML into your blog engine, HTML page, etc. It even allows for customization of fonts and sizes, just by renaming the .exe file. For example, renaming it from vs2html.exe to vs2html.arial.10.exe will make the default font Arial in 10 point size. My setting is Consolas 11.

The program he created is called VS2HTML, and it's freely available. You can download it here.

kick it on DotNetKicks.com

Labels: , , , , ,

posted by Jeff Blankenburg, 2:09 PM | link | 0 comments |

TUTORIAL #5: Calling Javascript From Silverlight 2

Tuesday, September 23, 2008

In this post, I want to show you how incredibly simple it is to call a Javascript function from the managed code of your Silverlight application. We'll also be able to retrieve a value from that function, and return it to Silverlight. If you're just hunting for the syntax, just jump to step #6. This post covers creating everything from scratch, in both VB and C#.

1) Create your Silverlight project and sister web site.

I've already documented creating a new Silverlight project here, so I'll let you read that one first, if necessary.

2) Let's write a "legacy" Javascript function.

We need a JS function to call, so let's make it interesting. Let's say that I have some code from a previous app that determines all of the prime numbers from 1 to 500. I don't necessarily want to rewrite that, so let's just reuse it. Here's the code:


//The purpose of this code is to find all of the prime numbers under 500.
//The definition of a prime number is one that is only divisible by 1 and itself.
//We are utilizing the Sieve of Eratosthenes to enhance our algorithm.
var primeArray = new Array();
var primecounter = -1;
var primeFlag = true;

function getPrimes(useri){
     primeArray.length = 0;
     primecounter = -1;
     var i = 500;
     if (useri != ""){
          i = useri;
     }
     for (j=1;j<=i;j++) checkForPrime(j);
          return primeArray.join(" ");
}
function integerCheck(newvalue){
     var regexp = /(^\d\d*$)/;
     if(regexp.exec(newvalue)) primeFlag = false;
}
function checkForPrime(j){
     primeFlag = true;
     for (k=0;k<=primecounter;k++){
          if ((primeArray[k] != "")&&(primeFlag)){
               if ((j/primeArray[k] != 1)&&(j/primeArray[k] != j)){
                    integerCheck(j/primeArray[k]);
               }
          }
     }
     if (primeFlag){
          primeArray[primecounter+1] = j;
          primecounter++;
     }
}


3) Add that JS code to our web page.

Just add a <script> block in the <head> of your web page, and put the above code inside. Done!

4) Now we need to write some XAML.

Open your Page.xaml file that was created for you, and let's add a button. We'll use this button's event handlers to call our Javascript function eventually. To add a button, here's the XAML I am using inside of the <Grid> I was provided:


<Button Width="100" Height="50" Content="Get Primes!" />


5) Add an event handler to our button.

In our button, add the "Click" property, and Intellisense will prompt you to create a "New Event Handler." This will create the method in the code behind file for you. Here's the new button XAML:


<Button Width="100" Height="50" Content="Get Primes!" Click="Button_Click" />


6) Time to call that Javascript function.

Jump into the code behind file for your XAML (page.xaml.cs or page.xaml.vb by default). There's a new method called Button_Click for you. We are going to write ONE line of code to make this happen. And here it is:

C#

HtmlPage.Window.Invoke("getPrimes");

VB

System.Windows.Browser.HtmlPage.Window.Invoke("getPrimes")


I kinda lied though on the 1 line of code thing. For C#, we also need the "using System.Windows.Browser;" statement. The "getPrimes" value we are passing is the name of the Javascript function we want to call. But this only gets us halfway there. My JS function creates a list of prime numbers and then sends them back as a return value. So we need to actually do something with this value.

7) Refactoring our code to use the return value.

So we know we can call a Javascript function, but returning the value is going to be a little more challenging. We need to capture the return value, cast it as a string (everything from Javascript is assumed to be an object), and display it in our Silverlight app. But let's make it a little more interesting. Let's also change things to pass parameters to our JS function as well.

First, we need some new XAML elements. I've added a <TextBlock> to my XAML page to display the primes, as well as a <TextBox> to gather the number of primes the user wants to generate. Here's the new XAML code:


<StackPanel x:Name="LayoutRoot" Background="White">
     <TextBlock Width="400" Text="Primes to what number?" TextAlignment="Center" />
     <TextBox Width="100" Height="24" x:Name="primecount" Margin="0,0,0,10" />
     <Button Width="100" Height="50" Content="Get Primes!" Click="Button_Click" />
     <TextBlock x:Name="primebox" Width="800" TextWrapping="Wrap" />
</StackPanel>

And now here's my new C# and VB code inside my Button_Click methods to pass our value and display this data:

C#

string primeArray = (string) HtmlPage.Window.Invoke("getPrimes", primecount.Text);
primebox.Text = primeArray;

VB

Dim primeArray = System.Windows.Browser.HtmlPage.Window.Invoke("getPrimes", primecount.Text)
primebox.Text = primeArray.ToString


What will happen in this scenario is that if the user provides a value, we will use it, and if they don't, we'll default to 500.

8) So let's run it!

That's it! We've successfully called a Javascript function from Silverlight (in both C# and VB), retrieved the value it created, and displayed it in our application. We also passed specific parameters to that Javascript function to influence its behavior. Click the Demo button to see it in action.



9) Source Code Links

I've provided the source code for this example in both C# and VB. Just click the appropriate button.

C#.NET Source Code VB.NET Source Code

kick it on DotNetKicks.com

Labels: , , , , , ,

posted by Jeff Blankenburg, 12:21 PM | link | 3 comments |

TUTORIAL #4: Showing Non-Silverlight Content To Users Without The Plugin

Monday, September 22, 2008


I just recently updated the navigation on my blog (http://www.jeffblankenburg.com) to be a nice Silverlight control, and realized that I was not really providing an optimal experience for those people that don't have the plugin installed. So since I had to go through it, I thought I would share with you how simple this actually is.

When you add a new Silverlight control to your page, this is what the code will look like:


<div id="silverlightControlHost">
     <object data="data:application/x-silverlight," type="application/x-silverlight-2-b2" width="880" height="60">
          <param name="source" value="ClientBin/JeffBlankenburg.com.xap"/>
          <param name="onerror" value="onSilverlightError" />
          <param name="background" value="white" />
     </object>
</div>


How To Add Your Non-Silverlight Content

Here's all you need to do to get it to work. Inside the <object> tag, after all of the <param> tags, just add your HTML. In my example, I have a different navigation in HTML for non-Silverlight users. It will display this content when the Silverlight plugin is absent.

Here's the new example, with my content included:


<div id="silverlightControlHost">
     <object data="data:application/x-silverlight," type="application/x-silverlight-2-b2" width="880" height="60">
          <param name="source" value="ClientBin/JeffBlankenburg.com.xap"/>
          <param name="onerror" value="onSilverlightError" />
          <param name="background" value="white" />
          <div id="sitetitle"><h1><a href="http://www.jeffblankenburg.com" class="style3">Blankenthoughts</a</h1><p class="style4"><strong>These are my thoughts. Nothing more.</strong></p></div><div id="menu"><a href="http://go.microsoft.com/fwlink/?LinkID=115261" style="text-decoration: none;"><img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none"/></a></div>
     </object>
</div>


How do I test this? I have the plugin installed!

That's easy in IE8. Just go to:

Tools > Internet Options > Programs > Manage Add-ons

and choose the Silverlight plugin. You can temporarily disable it there. Great new feature. Here's a picture of the screen (click to enlarge).



There you go. You can now create custom HTML to display for your users that have not yet installed the Silverlight plugin. I'd recommend letting them know they're missing out on the full experience, however, or they will never find your cool Silverlight control.

kick it on DotNetKicks.com

Labels: , , , ,

posted by Jeff Blankenburg, 11:41 AM | link | 2 comments |

TUTORIAL #3: Using Blogger with ASP.NET and Master Pages

Tuesday, September 16, 2008


I love the Blogger publishing engine, but I am frustrated by the apparent inability to do anything with .NET and Master Pages using it. This tutorial will show you how to get over that hurdle. A special thank you to Sarah Dutkiewicz for this awesome idea.

WHAT? A Microsoft guy is promoting a Google service? Yeah. I do that sometimes. I believe in using the best tool for the job, and in my case, Blogger fits that bill. There are plenty of blogging services out there, but many of them require me to also host a database, an application, etc., and I just don't want to have to deal with all of that. I want to write my posts, and know they ended up on my site. Plain and simple.

So let's talk about how we can use ASP.NET with Blogger to get a pretty nice scenario.

1) I am assuming you can set up a blog at Blogger.com.

Go to blogger.com. Follow instructions.

2) Create a new "Web Application" in Visual Studio.

I say to do a "Web Application" because I don't know what the future holds for your blog. If you want Silverlight, or more complicated things on your blog, it's a good place to start. You can use "New Web Site," but you may find your options limited later.

3) Create a new Master Page.

I titled my Master Page the same as my blog. Blankenthoughts.master. You can surely name it whatever you want. Delete all of the provided HTML that is written for you.

4) Let's get that blog template.

Go to the Template portion of your Dashboard for your blog, and copy the HTML that is provided. (I am assuming you like your current template. If you don't, take care of that first.) Now paste that code into your Master Page. It's gonna be gross. Also, as a backup, create a text file or HTML page or something and paste the code in there. And SAVE it. It never hurts to have a backup of the original.

5) Let's learn an awesome new keystroke.

So you've got that awfully unformatted HTML in your master page. Resist the urge to reformat it. I've got a faster solution. Press Ctrl + K and then Ctrl + D. Voila, your HTML is formatted.

6) Now we can save our master page.

Go ahead and save your master page, and we also need to create a new ASPX page based on that master page (make sure you check that checkbox). I called mine BloggerTemplate.aspx because this is going to hold the code that I paste back into Blogger. We're going to be jumping back and forth between the Master Page and the ASPX file quite a bit now, but it's just copying and pasting, so no biggie.

7) We need to move the <Blogger> tag, and all of its contents.

Somewhere in your Master Page now, there's a tag called <Blogger>. Cut (Ctrl + X) it from the opening tag to the closing one </Blogger>. In its place, create an <asp:ContentPlaceholder runat="server" ID="blogbody"> tag.

8) Create the content in our ASPX page.

We now need to replace that content in our BloggerTemplate.aspx file. Let's make one edit to our ASPX file before we paste that code in there. I changed my header values that are pre-populated for me. Here's the only line of code on my ASPX file right now:

<%@ Page MasterPageFile="~/Blankenthoughts.master" Title="<$BlogPageTitle$>" %>

Just under that, just add a:

<asp:Content ID="blogbody" ContentPlaceHolderID="blogbody" runat="server">

Inside that tag, paste the HTML we cut out of our Master Page. When we're done, Visual Studio is going to be FREAKING out over all of the proprietary Blogger tags we're using, but it will still build, and that's all that matters. Just trust that you did it right.

9) Now let's do the same thing for the other Blogger-specific stuff.

In my case, I also have some META information in the header of my page, archive links to the previous months that I have had posts, and also a section that shows my latest post titles. Each of these use Blogger-specific tags, and I'd rather get those out of my Master page and back into the Blogger template, where they belong. So create a ContentPlaceHolder for each of these sections, and copy that code into a Content tag in your BloggerTemplate.aspx file. Here's a link to see the source code of my final template file.

10) We're at step #10 already. Are we almost done?

Yes. But good things come to those who wait.

11) Now we need to change some settings.

In your Blogger Dashboard, we're going to have to change some of the settings. I'll just list them here, by the navigation you take to get to them.


  1. Settings > Publishing > Blog Filename: default.aspx

  2. Settings > Archiving > Archive Filename: archive.aspx

I am assuming you're hosting this blog in an environment that can process .NET pages...so IIS is kinda necessary.

12) Publish your website to your FTP site.

Because of the "We're going to delete everything" policy of Visual Studio, I prefer to move my files manually. I'd recommend this for you as well, or you'll be forced to publish from Blogger each time that you modify your website. (Because VS will delete EVERYTHING, not just the files it is overwriting.)

13) Publish your blog from Blogger for the last time.

You shouldn't be forced to publish your entire site anymore. Well, except when you post something new. But that can also be circumvented by posting from Live Writer. It's far more robust than the Blogger interface, and works great with the engine.

At this point, you should be up and running. I will be glad to coach you through this if you have issues, because I only encountered about 100 different issues specific to my hosting environment, folder structure, etc. Please let me know if this helped you out...it's good to know this stuff is providing some value.

kick it on DotNetKicks.com

Labels: , , , , ,

posted by Jeff Blankenburg, 11:17 AM | link | 5 comments |

TUTORIAL #2: Using Javascript To Call A WCF Web Service

Wednesday, September 03, 2008

Sometimes you just need to use Javascript. It's one of those things that web developers claim to hate, but secretly, I just hated the lack of tools support for it. That seems to be solved, at least for me.

Today I'm going to show you how to call your asynchronous web service from Javascript, and how we can incorporate JS Intellisense to make our job infinitely easier (one line of code, anyone?) The source code is provided at the end, in both C# and VB.NET.

1) Let's start with a new web application project.

Solution Explorer

2) Next, we're gonna need a web service to talk to.

image

Now, you may already be saying to yourself, "Jeff, this is all well and good, but I already have WCF services created. We don't all have the luxury of creating stuff from scratch each time!" I've got you covered. There's actually only one line of code that changes a WCF service into an AJAX-enabled WCF service. And here it is:

[ServiceContract(Namespace = "")]
 //The following line is the one you need!
 [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
 public class JeffsName
 {
  [OperationContract]
  public string GetJeffsName()
  {
   return "Jeff Blankenburg";
  }
 }


One you've got your WCF service up and rockin, we need to get it to DO something, right?



3) Getting our method to DO something

For this tutorial, I'm not going spend time talking to a database or anything extravagant. But I want to do more than return a name. I was talking with a friend of mine yesterday about why the nickel seems to be the rarest of coins in your pocket, and that inspired my method for this example.

<LONGSTORY TYPE="INTERESTING" VALUE="NOT IMPORTANT TO THE TUTORIAL">

Dan pinged me over IM to tell me about this guy who had started a game collecting money on the street. He called it the "Change Race." He wanted to see who could collect $100 faster by ONLY collecting money that was "found." It didn't count if you found $5 in an old coat from the previous winter, that was still your money.

Anyway, so Dan, who is known to like to try eccentric things like these, thought he would give it a go. In his coin finding history to this point, he discovered that he was finding significantly fewer nickels than any other coin. Here's the breakdown:

$0.25 - 7

$0.10 - 16

$0.05 - 6

$0.01 - 63

Yes, there are only 7 quarters, but who drops a quarter and leaves it? I certainly understand those pennies, however. But only 6 nickels? That seems surprising, as I'm calling it, "The Silverier, Fatter Penny."

So the conversation we had was about WHY there seems to be fewer nickels. We threw around many theories, but ultimately came up with the fact that there are fewer change scenarios where a nickel is necessary. In addition, there's rarely a time where you are going to get 2 nickels in change, because you're more likely to get a dime. Anyway, I'd love to see a debate about this in the comments. There's even a good article someone wrote about "The Mystery of the Vanishing Nickel."

</LONGSTORY>

So that story led me to think about the 99 change scenarios that are possible when receiving change from a cashier. 1 cent through 99 cents. Zero doesn't count because you would just get bills (or nothing at all.)

My web service is going to take an integer value and return the fewest number of coins necessary to make that change. If your integer is greater than 99, I just subtract out the dollars until we are left with the change.

Here's my web service method:

public class ChangeScenario
 {
  [OperationContract]
  public string GetMinimumCoins(int changevalue)
  {
   int quarter = 0;
   int dime = 0;
   int nickel = 0;
   int penny = 0;
   int tempvalue = changevalue;
   while (tempvalue > 0)
   {
    if (tempvalue >= 100)
    {
     tempvalue -= 100;
    }
    else if (tempvalue >= 25)
    {
     tempvalue -= 25;
     quarter += 1;
    }
    else if (tempvalue >= 10)
    {
     tempvalue -= 10;
     dime += 1;
    }
    else if (tempvalue >= 5)
    {
     tempvalue -= 5;
     nickel += 1;
    }
    else if (tempvalue >= 1)
    {
     tempvalue -= 1;
     penny += 1;
    }
   }
   return "You need " + changevalue + " cents in change.<BR/><BR/>You get " + quarter + " quarters, " + dime + " dimes, " + nickel + " nickels, and " + penny + " pennies";
  }

In all, I take an integer parameter, and return a string that represents the fewest coins that will satisfy that change scenario.

4) Making the page aware of the web service

I wish I could say that this was now as easy as writing a line of code in a script block and you're done. But it's maybe 5 lines of code more complicated than that. And most of those lines are dedicated to letting the .aspx page know that you want to talk to the web service.

So speaking of that, I will need to add my all-too-familiar-scriptmanager to the page, as well as a reference to the web service we want to use.

<form id="form1" runat="server">
    <asp:ScriptManager runat="server" ID="sm">
        <Services>
            <asp:ServiceReference Path="~/ChangeScenario.svc" />
        </Services>
    </asp:ScriptManager>
    <div id="valuebox">
        <a href="javascript:callWebService();">Click to call web service.</a>
    </div>
</form>
You'll notice that I also have a DIV tag in there, with an ANCHOR tag calling a Javascript function. Inside this function is where I will call my web service method.

5) Calling the web service from Javascript

Now I have created a Javascript function at the top of my page, and I need to make that call to my web service. The syntax is generally what you would expect to find:

<script language="javascript" type="text/javascript">
    function callWebService()
    {
        ChangeScenario.GetMinimumCoins(86, setText);
    }
 
    function setText(changetext)
    {
        var myElement = document.getElementById('valuebox');
        myElement.innerHTML = changetext;
    }
</script>

The one thing that stuck out to me in all of this was the second parameter in the method call. It's the name of another Javascript function. This new ability also gives us some new Intellisense.

Javascript Intellisense

The first value is the parameter that the web service method takes. In this case, it's even expecting an integer. The second is the name of the Javascript function you want to be called upon successful completion of the asynchronous call. The third is another JS function for when the call fails.

So, when we click our button, we call the callWebService() function, passing in an integer value to determine our change.

In turn, it returns our value successfully, and calls the setText() Javascript function with the parameter our method returns.

This function then renders that value as the HTML for the DIV we have on the page.

6) Summary of our adventure

As I demonstrated, in rather verbose fashion, it's pretty simple to talk to a web service from Javascript directly. Most of your effort will be spent writing a service far more valuable than mine. The nice part is that the asynchronicity of the calls is completely handled for you.

Please let me know if you have any questions...I'd be glad to help you out.

7) Let's see this code in action!

I have uploaded my sample application for demonstration of this code. It has been slightly modified, so that we call the web service 99 times, once for each "change scenario." One thing that I have noticed, at least in my environment, is that because we are making asynchronous calls, they don't always return in the order they were sent. So you'll see that, even though we are making the calls in the order from 1-99, they don't necessarily get written to the page in that order. We're just taking the data as it returns.

demo

8) Source Code Links

Even though I provided my examples above in C#, I have provided source code for both C# and VB implementations of this example. Enjoy!

C#.NET Source Code VB.NET Source Code



kick it on DotNetKicks.com

Labels: , , , , ,

posted by Jeff Blankenburg, 4:11 PM | link | 3 comments |

TUTORIAL #1: Creating a WCF Service For Silverlight 2 and SQL

Thursday, June 19, 2008

Today I'm going to show how to create a simple WCF service, and consume it from a Silverlight application. This is something you are going to need to do quite often, and if for no other reason, I am documenting this here so that I have it as a reference.

The first thing we need to do is create a Silverlight application. (In order to have all of the Silverlight 2 prerequisites, make sure you visit this page.)

1) I'm going to start from the beginning. First, we need to create a new Silverlight project. I'm naming mine JBWCFService.

Creating a new Silverlight project

2) We will then be prompted to create a web project to accompany our Silverlight project. I choose a Web Application Project from the dropdown.



3) Here is a view of what my solution explorer looks like after the projects are created. I have a Silverlight project called JBWCFService and a Web Application project called JBWCFServiceWeb, not surprisingly.



4) Next, I want to create a SQL database from which to get my data from. I'm not going to walk through all the steps of adding tables, columns, and data. You can certainly find that elsewhere. Here's my adding the SQL database to my project though...



5) OK, it's time to create our service. I'm naming my service MyNewService. It's just another thing to add to our project, so here we go:



6) Once the new service has been created, you will have a few new files in your project. In my case, they are named IMyNewService.cs, MyNewService.svc, and its code-behind, MyNewService.svc.cs. By default, the interface (IMyNewService.cs) will be open and ready for editing. They create a DoWork() method for you, but we're going to delete that and do something more interesting in a little while. First, we need to get LINQ up and running against our data. I am naming mine LINQClasses.



7) In addition to adding the class files necessary, this will also open the LINQ design surface by default. We can just drag items from our data structure right to the left half of the surface, creating ORM class structures that represent our data. In my example, I only have one table, profile, but we can do this for all of our tables, and stored procedures can be dragged to the right half of the surface, creating methods. I have already dragged my table over in the next screenshot (click to enlarge).



8) We also want to make sure that our data is unidirectionally serializable (I like big words). By clicking on the design surface (not one of the table boxes), you can get to the properties of the DataContext, and change the Serialization Mode to "Unidirectional."



9) Now we need our Silverlight project to become aware of our WCF service running in the web application project. To do this, we just need to add a new service reference to the Silverlight project. Click the "Discover" button to find it automatically. This will also automatically spin up a web server for your service to run in. I named my service reference MyNewServiceReference.



10) Ready to write some code? To this point, everything has been handled automatically for us. Now we have to get our hands dirty. Let's go back to our Service interface (IMyNewService.cs). In there, let's get rid of that DoWork() method. Instead, our method is going to return a List of profiles from the database, based on our new classes that were created for us. Because this is an interface, we don't define the actual functionality of the method here, just it's signature. I named my method GetProfilesByLastName.



11) Ok, that was exhausting. Let's have the IDE write some more code for us now. Let's open the code-behind file for MyNewService.svc (MyNewService.svc.cs). You can see that it inherits from the interface we just defined, so right click on the name of the interface, and have it implement the interface for you.



12) Now you've got the shell for the method. We just need to tell this method what to do. Here's where the LINQ comes into play. We need to get a reference to our DataContext from earlier, and then I wrote a simple query to retrieve names from the database based on a last name query. Finally, we return our list of data.



13) Each time we update our service, we will need to update our service reference in the Silverlight project, so that it sees our new methods. Just right click on the service reference and choose "Update Service Reference." Also, we have one small change we need to make to our web.config file as well. If you've been following the instructions, then you can scroll down to the bottom of your web.config and look for the <endpoint binding="wsHttpBinding" /> property. Silverlight only currently supports basicHttpBinding, so we need to change it to that.



14) Next, we need to add one more reference to our Silverlight project before we can finally start working with the XAML. We need to add a reference to System.Windows.Controls.Data so that we can use the DataGrid control in our interface.



15) XAML time. Kinda. We need to include that reference as a namespace in our Page.xaml document. OK, now we can add some controls to our page. I also added a Button, a TextBox, and a DataGrid, inside a couple of StackPanels, for layout purposes.



16) Now, we need to call that method in our service and populate that grid. The first thing we need to do is instantiate our ServiceClient. Now, since we are calling this service asynchronously, we also need to set up an event handler to know when our data has returned so that we can update the DataGrid. There's an excellent bit of shorthand for creating this code automatically. My screenshot shows all of the code I will need, but for the line that starts:

sc.GetProfilesByLastName +=

I only actually typed what is above. After that, I pressed the Tab key twice. The first press of Tab actually finishes out my EventHandler statement. The second Tab press creates my EventHandler method, so that I can add the guts. Finally in my Button_Click method, I need to call the GetProfilesByLastName asynchronously, passing in the value from my TextBox, named DataEntry.



17) The last little touch we need to put on this application is the actual binding of the data to our DataGrid, and we'll do that in the new EventHandler method that was created for us. There's just one line of code in the method:

DataGrid.ItemsSource = e.Result;



So, there you have it. We've created a WCF service that uses LINQ to talk to a SQL server, and a Silverlight 2 application that consumes that service and renders the result. Not bad for 17 steps, and only a few lines of code.

Click here to download the solution files.

Labels: , , , , , , ,

posted by Jeff Blankenburg, 11:34 AM | link | 9 comments |

Search

My Sponsor


My Badges



Follow Jeff Blankenburg on Twitter