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!

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 #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 |

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 |

Free Software!!!

Friday, February 22, 2008

As I hope you'll recall, we had some Visual Studio 2008 Install Fests late last fall. These events sold out in under 48 hours. We gave away 525 disks that could be redeemed for a full version of VS2008 Professional.

I've just heard back from the organization that was running this effort for us, and there's been a surprisingly LOW redemption rate. This is just a friendly reminder to everyone that has a Trial disc and has not gone online to redeem it for their full version.

THAT OFFER EXPIRES ON MONDAY, FEBRUARY 25, 2008!

Please make sure you get yours in. I'd hate to see you miss out on this offer.

Labels: , ,

posted by Jeff Blankenburg, 10:06 AM | link | 9 comments |

Visual Studio Has Arrived!

Monday, February 18, 2008


For those of you that had the good fortune to get over to one of the Visual Studio 2008 Install Fests we had late last year, today's your day!

The full licensed copy of VS2008 Pro has been mailed, and you should be receiving it as soon as TODAY.

Keep an eye on your mailboxes...

Labels: , ,

posted by Jeff Blankenburg, 1:31 PM | link | 1 comments |

Columbus .NET Developer's Group Excitement!

Wednesday, November 28, 2007

CONDG is having their last meeting of the year on Thursday, December 6th. Though their site is experiencing "technical difficulties," it contains all of the information about their meetings. Since it's down, I'll post the information here as well:

CONDG Meeting
http://www.condg.org
12/6/2007 6:00 PM
Microsoft Building
8800 Lyra Ave
Columbus, OH 43240

The reason I am promoting this is severalfold.

1) I think it's important that developers participate as a community. There is so much to learn from your fellow developers that you would be hard-pressed to figure out on your own. Much like Wikipedia, it only truly works when everyone is participating.

2) It's going to be a fun night. We'll have a speaker talking about Visual Studio 2008 and the 3.5 framework. We'll have XBoxes with Guitar Hero III and Halo set up. We'll have food to eat and beverages to consume. And a room full of developers with the smarts to teach you something you didn't know before you got there.

3) I'm going to be giving away copies of Visual Studio. Everyone that comes to the meeting will get a copy of a 90-day trial of Visual Studio 2008 Professional. Everyone that REGISTERS AND ATTENDS will be given a code to redeem for a full license of Visual Studio 2008 Pro when it is available.

So the next question you may have is...HOW DO I REGISTER? Well, readers, here's how. Click on the link below to be taken to the registration site. That's all.

http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032361590&Culture=en-US

Also, don't be discouraged if you find out the registration is closed. I will also have a waitlist, because it's certain that some of the folks that register won't be able to attend. We'll take names at the door of those individuals that were unable to register, and those will go on a first-come, first-served basis.

I look forward to seeing all of you at the event. It's going to be a fun night.

Labels: , ,

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

Want a free copy of Visual Studio 2008 Pro?

Tuesday, November 27, 2007



So some of you may have heard rumblings about some piece of software being released recently, and some of you even chided me for not having a super mega blog announcement about it.

Visual Studio 2008 has RTMed!


Now, in other news, we have put together a few events to give away copies of Visual Studio 2008 Pro to y'all. (I'm currently in Texas...my apologies.)

We will be holding a Holiday Bowl-O-Rama & InstallFest event in Nashville, TN on December 3rd, and another one in Detroit, MI on December 7th. These events MUST be registered for in order to get the free bits, so here's the links to these events:

Nashville, TN - December 3
Detroit, MI - December 7

We will be handing out Visual Studio 2008 Pro (90-day trial) disks to everyone that attends. However, we are only able to give away a full version (available in early 2008) to those individuals that register using the links above, AND attend. Registration alone is not going to be enough.

As some of you loyal readers know, I went bowling a few weeks ago, and declared myself the best bowler that reads this blog. This is your opportunity to prove me wrong. These events will be held at bowling alleys, and we'll be picking up the costs of bowling and shoes, and food will be provided as well. All you need to do is show up, and hurl that ball down the alley.

If you can beat my 2-game average, I will have a special gift for you. (This is above and beyond the Visual Studio software you're going to receive). I'm not going to be promoting this contest at the events, so you'll have to come find me with your proof of score. It's one of the many benefits of being a regular reader of this blog.

So, go register for your event. Tell your colleages to register. It's gonna be a blast. We'll also have XBoxes with Guitar Hero III and Halo 3 available for playing.

Labels: , , ,

posted by Jeff Blankenburg, 10:13 AM | link | 6 comments |

Search

My Sponsor


My Badges



Follow Jeff Blankenburg on Twitter