Feed Icon  

Contact

  • Bryant Likes
  • Send mail to the author(s) E-mail
  • twitter
  • View Bryant Likes's profile on LinkedIn
  • del.icio.us
Get Microsoft Silverlight
by clicking "Install Microsoft Silverlight" you accept the
Silverlight license agreement

Hosting By

Hot Topics

Tags

Open Source Projects

Archives

Ads

Previous Page Page 2 of 5 in the ASPNetWebServices category(RSS) Next Page

Simulating Data Grids in WPF/E - Part 1

Posted in ASP.Net/Web Services | WPF/E at Thursday, 08 February 2007 08:11 Pacific Standard Time

The source code for this article can be downloaded here.

While there is no official Data Grid in Windows Presentation Foundation (WPF) you can still layout your data quite easily using the Grid Panel. In WPF/E (E for Everywhere) there is no Grid Panel and you must lay everything out using a Canvas where you must specify the absolute position of every item. WPF/E also has no method of data binding, so creating a data grid is not as simple as DataGrid.DataBind().

In this article I will demonstrate how to simulate both a grid layout and data binding in WPF/E. This will be the first article in the series and will only show the basics with later articles taking this approach even further. Before we get started you will need the following items:

  • Northwind sample database - For this article you can host this in SQL Server 2005, SQL Server Express, or SQL Server 2000. However, future articles will make use of SQL Server 2005 features and the source code was coded against SQL Server 2005.
  • WPF/E Feb CTP SDK - You will need the SDK and the aghost.js file from the SDK.
  • ASP.Net AJAX 1.0 - I also reference the ASP.Net AJAX Futures CTP in the project, but for this article you only need the base 1.0 features.
  • Enterprise Library for .NET Framework 2.0 - This makes our calls to SQL Server much simpler.

Setting Up The Database

The first step is to attach the database to the SQL Server. In SQL Server 2005 you need to open up the SQL Server Management Studio, right click Databases under your server, and select Attach. Browse the the MDF file that was extracted from the Northwind sample database installer. We will be using the Photo column of the Employees table for our images (yes, they are terrible images, but for a demo they will work). However, there are two problems with the data in the Photo column (1) it has a header that makes it so you can load it in .NET and (2) it is a GIF image which isn't supported by WPF/E. So to get around this issue I wrote a console application that strips off the first 78 bytes and then saves the image back as a JPEG (it is included in the source code). So you will need to run that application against your database to convert the images to the right format.

The process for doing this with SQL Express is probably a little different and I leave this as an exercise for the reader (of course you can just add your own images instead using the ones in the database).

The Website Project

Next we can turn our attention to the website project. The project is made up of the following items:

  • Default.aspx - the only page in the site
  • EmployeeService.asmx - the web service that we will be calling
  • PhotoHandler.ashx - the IHTTPHandler that returns the images from the database
  • Web.config - the configuration file for the website
  • App_Code/Employee.cs - the Employee object
  • App_Code/EmployeeData.cs - the Data Access Layer (DAL) for Employee data
  • App_Code/EmployeeService.cs - the code behind for the web service
  • scripts/aghost.js - The WPF/E aghost file from the Feb CTP (part of the SDK)
  • scripts/grid.js - The javascript that we will use to build our grid
  • xaml/grid.xaml - The xaml for our grid (not much there)

I'm not going to cover how the DAL works or what the photo http handler is doing since that is outside the scope of this article and they are fairly simple. We will start with taking a look at the Default.aspx page since that is where everything begins. There are three important things to look at in this page. First, you will notice that we reference both the aghost.js file and the grid.js file. Second, we have the ASP.Net AJAX script manager which we point to our EmployeeService web service url. This tells ASP.NET AJAX to build a javascript proxy for our webservice which we can call via javascript. This is how we will get our list of employees out of the database and into our WPF/E data grid. Third we have the script to create the WPF/E control which makes a call to the code in the aghost.js file. This will load up our grid.xaml which is what we will look at next.

Building the Data Grid

The base of our data grid is the grid.xaml file. If you open this file you will see that it is pretty much an empty canvas. The two important things for this file are the Loaded="javascript:loaded" and the x:Name="root". The Loaded event gets fired when the control has finished loading the canvas. This is important because this is what will trigger the building of the data grid. We give the canvas a name so that we can add the elements of our grid to it at run time.

The javascript loaded function is found in the grid.js file. This file is where the action happens. The loaded function is very basic in that it simply creates a new instance of the javascript grid object that is defined below it. I try to encapsulate all my javascript code in to objects since it helps keep the code neat and I find it smells better than a bunch of functions by themselves.

In the grid object's constructor we define three properties: the WPF/E control, the root canvas, and the item template. If you want to change how your data grid items look you can tweak the item template. After defining these items we make a call to EmployeeService.GetEmployees. This is the javascript proxy that was created for us by ASP.Net AJAX. It is an asynchronous call and we pass to it the method we want to be called when the service returns. In this case we want it to call the loadEmployees method of our grid object, but we really want it to call the method on the grid object that we are currently using. In order to do this we use the delegate object which I borrowed from the WPFEPad project (which BTW is a great project to dissect in order to learn about WPF/E and javascript).

When the call returns it calls our loadEmployees method where we will start the process of adding the employees to our data grid. At the top of the method are some variables which you can tweak to change the spacing and layout of our grid. Make sure the itemWidth is the same as the Width of the canvas in the template, otherwise things will overlap. The javascript proxy returns an array of Employee objects (as defined in the Employee.cs file) which we will loop through, apply to the template to create the Xaml for each Employee, and then add back to the canvas with the appropriate Canvas.Top and Canvas.Left settings. Note that we reference the ActualWidth of the control to determine how much space we have to place the employees.

After we have added the employee xaml to the canvas, we find the name TextBlock (as defined by our template) and center it using the ActualWidth of the TextBlock. This is how you center text in WPF/E since there is currently no alignment property for TextBlocks.

Finally we check to see where we are to see if we need to start a new row of employees. If you run the example you should get something that looks like the following in your browser:

So you now have a very simple data grid created using WPF/E and ASP.Net AJAX.

Next Steps

At this point the grid is very simple so there are quite a few enhancements that we could add. Here are a few of the ones that I have in mind:

  • Paging and Sorting
  • Click Events that allow you to see the Employee details
  • Mouseover effects
  • Handle resizes and full screen

Another thing to keep in mind is that we could build a lot of this using an ASP.Net page that generates the Xaml and only use the javascript code to line the items up. This is another approach which I will leave as an exercise for you. :)

Technorati Tags: WPF/E

WPF/E + ASP.NET AJAX, Better Together

Posted in ASP.Net/Web Services | Avanade | WPF/E at Thursday, 25 January 2007 04:39 Pacific Standard Time

One of my side projects at work has been a social website for the SoCal solution developers. I decided the site would be a great chance to learn more about WPF/E as well as ASP.NET AJAX so I've been making heavy use of both on the site. One of the last version 1.0 features that I wanted to finish was the login page which was pretty ugly (until today). I was hoping to use a pure WPF/E solution for the login itself, but WPF/E doesn't support things like textboxes yet, so I had to use plain old HTML as well. I also tried to make use of dog ears in the animations and I think that I succeeded.

You can give it a try and see the animations in action (but you shouldn't be able to log in :). I'm planning on creating a demo version of the site that can be used for demos that won't have real people's info in it, but for now you'll just have to get back on the invalid login example. I built the buttons in notepad but I followed Lee's demonstration on how to create animated buttons in WPF and just tweaked it to use in WPF/E. I didn't complete the button down animations yet, but the mouseover animations work great.

For the dog ears effect of the text flying in and out I used my DoubleAnimationUsingKeyFrames technique from my previous post and just added a little bit of bounce to the animation. I think it works. For the AJAXish wait icon I downloaded an icon from this site, converted it to a PNG file, and then added a RotateTransform with an animation (using the CenterX and CenterY properties to make it spin).

Inside the site I've also used a lot of ASP.NET AJAX and WPF/E, but for now I'm going to keep that under wraps. But I will make a demo site soon. Let me know what you think of the login.

WPF/E CSModule Released

Posted in ASP.Net/Web Services | WPF/E at Thursday, 18 January 2007 04:27 Pacific Standard Time

I just posted my WPF/E CSModule that I created to display WPF/E content on Community Server blogs. You can download the module and the source code here. It will allow you to display multiple WPF/E items in a single post and puts links on the posts when they are viewed in a feed reader. The source code includes everything except my tests. You can view examples of the module in action here and here.

My First WPF/E App

Posted in ASP.Net/Web Services | Avanade | WPF | WPF/E at Thursday, 14 December 2006 07:27 Pacific Standard Time

I've always thought that Flash was cool. When I was in college I purchased a copy of Macromedia studio at the academic price and tried to create some Flash animations for a website. However, I'm not a designer and the learning curve was too much for me at the time, so Flash didn't stick with me.

A couple of projects back I spent a lot of time with WPF since the client portion of the application was going to be built with WPF. Armed with a basic knowledge of WPF, I thought I would give WPF/E a try. One of the big advantages of WPF/E is that if you like what someone else has done you can just take a look at their XAML. So to get started on my WPF/E project I took a look at the WPF/E Egg Timer (via Tim) and the WPF Blog's Header. You can download the XAML and the JavaScript for both to see how they work. I also read through this article on getting started with WPF/E which includes IIS configuration information.

One of the projects that I've been working on in my spare time is a social website for the Avanade solution developers in Southern California. So far I don't have much to show except a cool url and now a very simple WPF/E animation. You can check it out at http://wsup.la.

It is just a place holder for now, but it was still fun to create. In addition to the links above, I also used:

Since WPF/E is so easy to create (and edit) I'm guessing we will be seeing a lot of it in the near future.

Is That a Runtime in Your Browser?

Posted in ASP.Net/Web Services | Avanade | .NET | WPF at Thursday, 24 August 2006 03:37 Pacific Daylight Time

In my life as a developer I have somehow never been on a project where I was creating a windows forms application (or a VB6 UI for that matter) AFAIR. Somehow I was always doing either ASP, ASP.NET, or some backend application with no real UI. My current project is different in that it is a smart client application. However, the client really wants to use WPF for the UI.

The more I understand WPF, the more I feel like I'm building a web application more than a forms application. The UI is all based on markup and you have databinding that seems very ASP.Net like. The line is blurred even more when you add in XBAPs which means you can run the WPF directly in the browser. However, WPF application development seems to blast past ASP.NET development at this point.

On my last project I built a really simple management UI using ASP.Net and Atlas. As much as Atlas tries to integrate AJAX into ASP.Net, I still felt like I was back in my ASP spaghetti code days. Kyle Huntley, a fellow Avanuat, makes a similar observation:

Atlas / Ajax does not represent any “Best Practices” in development from a purely technical standpoint; there are better ways to do it all. It is the unfortunate reality that the industry has been unable to settle on a single well-conceived runtime environment and has instead taken a drunkard’s walk to arrive at a very unappealing, but relatively standard, programming environment. Ajax is simply a way of trying to paper over the “poor” client characteristics of the browser / markup technology rootstock.

WPF can give you a richer experience than AJAX and without all the spaghetti mess. As another fellow Avanuat TSHAK says:

In the midst of all of the hype around the cool hacks that you can with a web browser, it is important not to ignore the innovation happening around application development on the Windows platform.

I definitely agree that WPF is taking us in the right direction and gives us a much cleaner development story than ASP.NET/Ajax. However, you might not have the option of assuming .NET 3.0 on the client for quite some time. But if you do have control over what is on the client, then WPF is a great choice for smart client applications (or is it a rich client?). Then you have the choice of running in the browser or not which gives you lots of great options.

So I personally think the runtime is the way to go, whether or not you run it in the browser. Now it is just a question of how well Microsoft drives WPF adoption and how Microsoft developers adapt to this new paradigm of client UI development.

Technorati Tags: - -

Bryant Likes's Blog v2.1

Posted in General | ASP.Net/Web Services at Monday, 14 August 2006 05:55 Pacific Daylight Time

Just upgraded the sqlxml.org blogs to community server 2.1. One of the features that I was interested in was the Feedburner support. I was thinking of using feedburner a long time ago, but I really didn't feel like figuring out all the issues around it. Now it just works! Great job Telligent!

I really like the new skins that ship with this release as well. I even changed my google ads to work with this new layout (and ditched the yahoo ads).

I'm writing this post from Windows Live Writer, which I really like so far (hope it works).

Update: I forgot to mention that I used Sean Winstead's post on using google adsense in community server (and even stole some of his style) to setup my adsense. Thanks!

Workflow 2.2 Available!

Posted in ASP.Net/Web Services | WF at Monday, 01 May 2006 03:17 Pacific Daylight Time

From WindowsWorkflow.Net:

Windows Workflow Foundation Beta 2.2 is now available for download on MSDN at this location. Please note that this release is not compatible with the February CTP of WinFx and must be installed on a machine without the February CTP. For more details, please refer to the installation instructions. While this installation is marked as the "Microsoft Visual Studio 2005 Extensions for Windows Workflow Foundation Beta 2.2", it contains the runtime and documentation components as well.

Hmm... I hope this doesn't mean I have to flatten everything and start over just to install this update. However, this is exciting since it should include the ASP.Net asynchronous background workflow support I was looking for.

Update: You can upgrade to this version by following the instructions. However, I misread Paul's post about "functionality was added after beta 2.2 was released" [emphasis mine]. I read that and thought it was going to be in 2.2. :)

Update2: I don't know why this suddenly appeared as new to me when it has been out for quite some time! For some reason when I went to the homepage it looked different so I thought it was a newer release. I guess I have to have a good laugh at my own expense from time to time. :)

ASP.Net Background Workflows

Posted in BizTalk | ASP.Net/Web Services | WF at Tuesday, 25 April 2006 02:41 Pacific Daylight Time

I really like what the on10 guys did with the on10 website. The login UI is the best I've seen and I really like the mashup they do on the profile page. I like it all so much that I've been working hard to duplicate a lot of it for use on some of my hobby sites.

I've emailed back and forth with the on10 team about how they did certain things and they have been very generous with their answers. One of the things I was curious about was how they handled the background tasks for the user profiles. Obviously, when you update your profile they don't make you wait while they lookup your location, blog, blog posts, and other details for that page. There is no point in snappy AJAX if you make the user wait for a process like that to happen. So how do they handle it?

Duncan suggested that a windows service would work pretty well or a console application that you schedule (which is something I've used in the past). However, for on10 they use a form of background processing tasks based on some of Rob Howard's work (see these slides and demo code for some examples of background threads in ASP.Net). This works well for them and the setup they have with the on10 web servers.

However, what if you didn't want to deal with spawning off threads and putting timers into your ASP.Net application? Is there some other way to do background processing with ASP.Net? What about Windows Workflow Foundation (WF)?

First off, why would you want to use a workflow for something like this? Well, I think workflows are nice because when you come back to the code six months later and want to do one more thing when the user signs up, it is very easy to look at the process and add something more. So the workflow is a nice addition for things like this.

So what are the options with a workflow? Well if you read this article by Dino you will get a good idea about how to use workflows in ASP.Net. However, there is one problem with the code in the article: it is being executed while the user waits for the response to come back. This is fine in a lot of cases, but what if you're looking at the case I'm talking about?

In this case you need to use the DefaultWorkflowSchedulerService instead of the ManualWorkflowSchedulerService. The Default service will allow WF to manage the execution of your workflow and it will spin up threads as needed to process it (and the user won't wait). However, ASP.Net doesn't like other processes spinning up a bunch of threads. I posted a question about using this method to the Advanced Workflow blog and as I was working on this post my question was answered. :)

So while I was able to get this working (and I fell in love with workflows in the process), it is not the recommended solution. In fact, the recommended solution is to put the workflow in a windows service and map to it with Indigo (Windows Communication Foundation).

I guess this means I'm going to learn Indigo, because I definately like workflows...

Update: From Moustafa Khalil Ahmed I found another article on ASP.Net workflows from Paul Andrews. Apparently the WF team has made some changes to the ManualWorkflowSchedulerService so that it can run as a background process (meaning it will work much like the default scheduler) in ASP.Net. This is great news! I have actually already coded my solution as a Windows Service that is called via Indigo. However, I'm definately going to change it back because the whole windows service thing really complicates my project when it comes to testing and deployment. Thanks guys, it worked out perfectly, I was forced to learn more about Indigo and then I get to go back to my simple solution!

Right On10

Posted in General | ASP.Net/Web Services at Tuesday, 14 March 2006 01:58 Pacific Standard Time

Watching this video about on10.net and I must say that I'm pretty impressed. It is fun to see Microsoft building a site like this. If you haven't seen the site yet, you should check it out. I'm thinking I'm going to be checking out their souce so that I can pull in that same MSN search that they showed in the video. Here is Tuesday's video which should add a trackback to this post:

 

Update: Hmm.. not sure if it is working. Here is the link to the video in case the script doesn't work...

Update2: I give up. I can't figure out how to get CS to let me post a script tag in my post. There doesn't seem to be any setting to turn this off. I also tried adding it to my news section, which didn't work, and to the blog skin itself, which for some strange reason didn't work either. Oh well...

Update3: Keyvan pointed me to his post as a possible fix for the script tag suppression issue, but now I can implement inline styles but still can't get the script tag to show up...

Update4: Thanks to Keyvan I figured it out. So now I can put scripts tags in my posts, but for some reason the video still doesn't show up. :(

Update5: Now it is working! Cool!

Creating a UL SiteMap Menu

Posted in ASP.Net/Web Services at Friday, 17 February 2006 07:03 Pacific Standard Time

It's been awhile since I last bloged! I'm still alive and still working on my ASP.Net 2.0 project.

Today I was working on a new menu and I wanted to use the unordered list approach (UL) and I wanted it to be driven by the web.sitemap file. After some googling I came across this post by Danny Chen which uses a repeater control and then goes on to create a template control. Close to what I wanted, but I really didn't need a template, just a simple list with a class declaration on the active menu item. I also found this post by Jeff Lynch which talked about the need for a simple sitemap menu. So I created one. :)

The code is pretty simple. It is made up of two classes and it currently renders all the items in the sitemap starting with the root. This suites my needs perfectly so I'm not adding any other features, but it would be very easy to customize this to add more hierarchies. Below is the code for the SimpleSiteMenu and SimpleMenuItem controls:

 

using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI.WebControls;
using System.Collections;
using System.Web.UI;
using System.Web;

namespace DavisTwelve.Web.Controls
{
    
public class SimpleSiteMenu : CompositeDataBoundControl
    {

        
private string _activeCssClass;

        
public string ActiveItemCssClass
        {
            
get { return _activeCssClass; }
            
set { _activeCssClass = value; }
        }

        
private string _itemCssClass;

        
public string ItemCssClass
        {
            
get { return _itemCssClass; }
            
set { _itemCssClass = value; }
        }

        
private int AddChildNodes(SiteMapNode node, SiteMapNode current)
        {
            
int count = 0;

            
foreach (SiteMapNode child in node.ChildNodes)
            {
                count++;
                Controls.Add(
new SimpleMenuItem(child, GetCssClass(child, current)));
                count += AddChildNodes(child, current);
            }

            
return count;
        }

        
private string GetCssClass(SiteMapNode node, SiteMapNode current)
        {
            
if (node == current)
            {
                
return _activeCssClass ?? _itemCssClass;
            }
            
else
            {
                
return _itemCssClass;
            }
        }

        
protected override int CreateChildControls(IEnumerable dataSource, bool dataBinding)
        {
            
int count = 0;
            
SiteMapNode current = null;
            
SiteMapNodeCollection nodes = dataSource as SiteMapNodeCollection;
            
SiteMapDataSource siteMap = this.GetDataSource() as SiteMapDataSource;

            
if (dataBinding && nodes != null)
            {
                
if (siteMap != null)
                {
                    current = siteMap.Provider.CurrentNode;
                }
                
                
foreach (SiteMapNode node in nodes)
                {
                    count++;
                    Controls.Add(
new SimpleMenuItem(node, GetCssClass(node, current)));
                    count += AddChildNodes(node, current);
                }
            }

            
return count;
        }

        
public override void RenderBeginTag(System.Web.UI.HtmlTextWriter writer)
        {
            writer.AddAttribute(
HtmlTextWriterAttribute.Id, this.ClientID);
            writer.RenderBeginTag(
HtmlTextWriterTag.Ul);
        }

        
public override void RenderEndTag(System.Web.UI.HtmlTextWriter writer)
        {
            writer.RenderEndTag();
        }
    }
}

 

using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI.WebControls;
using System.Web.UI;
using System.Web;

namespace DavisTwelve.Web.Controls
{
    
public class SimpleMenuItem : WebControl
    {
        
string _url;
        
string _title;
        
string _cssClass;

        
public SimpleMenuItem(SiteMapNode node, string cssClass)
        {
            _url = node.Url;
            _title = node.Title;
            _cssClass = cssClass;
        }

        
protected override void Render(HtmlTextWriter writer)
        {
            
if (!string.IsNullOrEmpty(_cssClass))
            {
                writer.AddAttribute(
HtmlTextWriterAttribute.Class, _cssClass);
            }
            writer.RenderBeginTag(
HtmlTextWriterTag.Li);
            writer.AddAttribute(
HtmlTextWriterAttribute.Href, _url);
            writer.RenderBeginTag(
HtmlTextWriterTag.A);
            writer.Write(_title);
            writer.RenderEndTag();
// a
            writer.RenderEndTag(); // li
            
        }
    }
}

To use the control just add a SiteMapDataSource to the page and then set the DataSourceID to the data source's id.

BTW - Thanks to Jeff Atwood for the cool copy as RTF macro.

 

Previous Page Page 2 of 5 in the ASPNetWebServices category(RSS) Next Page