| Comments

I was talking with a good friend the other day about some feedback about DataForm.  It’s great to get raw and honest feedback…that’s where you improve more than ‘it sucks’ type feedback.  One of the use cases he felt would be common with the Silverlight DataForm control (available in the Silverlight Toolkit) was the concept of confirming the delete action.  I agreed as well that confirming permanent delete actions is a common line-of-business application pattern.  It got me thinking about some things…

The Problem

DataForm is a great control.  I love it.  It will benefit many developers in the simplest applications quickly as well as some in the most complex applications with some additional configuration.  For the purposes of this demonstration, I’ll talk about the simplest scenario.  DataForm has build in controls for navigating a bound data set, as well as adding and deleting new items.  It is the deleting I’d like to concentrate on here. 

When DeleteItem is called on DataForm (via the built-in toolbar or via your own methods), it deletes the current item.  After all, that’s what you told it to do!  The problem is that the delete is fast and there is no easy “undo” method. 

The Helper

Luckily, DataForm provides a method interceptor for us: DeletingItem.  This event fires when DeleteItem is called and tells you: Hey, I’m about to delete the current item.  If you want to do anything about that, now is the time.  So there you have it…you can prevent the delete because there is a CancelEventArgs parameter passed in to cancel the remaining event.  So what would you do in DeletingItem?

Solution 1: Go modal

One thing you can do is leverage a modal dialog.  This would block the event until a modal dialog response is provided for you to investigate.  Here’s an example of what you might do in DeletingItem:

   1: private void PeopleBrowser_DeletingItem(object sender, System.ComponentModel.CancelEventArgs e)
   2: {
   3:     if (MessageBox.Show("Are you sure you want to delete this item?\nThis cannot be undone", "Delete Item", MessageBoxButton.OKCancel) == MessageBoxResult.Cancel)
   4:     {
   5:         e.Cancel = true;
   6:     }
   7: }

So what’s the problem with this one?  Nothing really.  The dialog would show, giving your user a chance to react and block the delete call until an OK is received (it cancels the event if Cancel is clicked).  But let’s look what it generates from a user experience standpoint:

confirm delete with MessageBox

Hmm, maybe there is a problem.  First, it says OK or Cancel…not really a “Yes or No” response the user is really looking for.  Second, using MessageBox will focus the dialog in the center of your window and not center of parent (or calling control).  These two things make it less ideal in my opinion.  The major positive here is twofold: it works and it’s truly modal (thus blocking the call to delete).

Solution 2: Pimp your dialog, but also your code

Silverlight is all about improving the user experience right?  Changing things around and differentiating the RIA?  So let’s use that mantra to think what we could do here.  Silverlight 3 provides a new control, ChildWindow that you could use in this instance.  It provides a modal-like experience to the end user (blocking other UI components) and gives them a focused area to provide a response.

NOTE: I’ve refactored ChildWindow into something I call “FloatableWindow” for MDI or other type interfaces.  I’ve provided my code for you to use on the .  I’ve also added a work item on the Silverlight Toolkit so if you like the idea, please vote on it!

The challenge with ChildWindow is that while it exhibits all the UI experience of a modal dialog, behind the scenes it is asynchronous.  This means that if you put a Show() call to a ChildWindow in your code, that your next line of code will run as well.

NOTE: If you think this should be changed, consider voting on the Silverlight Toolkit project for this item: ChildWindow – make it modal.

We can, however, still be creative.  Let’s explore an idea here.  We know that we have the DeletingItem event we can still tap into, so we can trigger our implemented ChildWindow like this:

   1: private void PeopleBrowser_DeletingItem(object sender, System.ComponentModel.CancelEventArgs e)
   2: {
   3:     ConfirmDialog cd = new ConfirmDialog();
   4:     cd.Show();
   5: }

The problem is that unless we cancel the event, the delete will still happen (and you can see it happen from behind the ChildWindow even…frustrating!  The ChildWindow.DialogResult is essentially worthless to us right now.  Let’s think creatively though.  What I did was create a member variable called _delete and set it to false.  This tells the DeletingItem event whether or not it really should delete.  It sounds dumb, I know, but work with me.

Now when we call DeletingItem, we check to see if we really should delete or not (really we check to see if we should cancel the event).  If we are still in “false” mode, then we shouldn’t delete but should show our confirmation window and cancel the DeletingItem event.  That’s great, but we still need to get the user response from the window!  We then need to tap into the ChildWindow.Closed event and get the DialogResult from there.  In the Closed event we can see if they confirmed the delete.  If they cancelled the delete, we do nothing further.  If they said “Yes” then we need to change our _delete variable and call DeleteItem on our DataForm again.  Now our DeletingItem handler knows we can successfully continue.

Sound fuzzy?  Sound like a hack?  Maybe so, but it works.  This gives us the opportunity to create a customized user experience for the confirmation.  Now I’m a crappy designer, but to make the point clear to differntiate from simple MessageBox, my ChildWindow has a flashing background and blurs the DataForm.  Yeah, it’s obnoxious, but that is the point for this demonstration!  Here’s the complete code for this solution:

   1: private bool _delete = false;
   2:  
   3: private void PeopleBrowser_DeletingItem(object sender, System.ComponentModel.CancelEventArgs e)
   4: {
   5:     if (!_delete)
   6:     {
   7:         Person p = PeopleBrowser.CurrentItem as Person;
   8:         ConfirmDialog cd = new ConfirmDialog();
   9:         cd.Closed += new EventHandler(cd_Closed);
  10:         cd.Title = string.Format("Delete {0} {1}?", p.FirstName, p.LastName);
  11:         BlurEffect b = new BlurEffect();
  12:         b.Radius = 10;
  13:         PeopleBrowser.Effect = b;
  14:         cd.Show();
  15:         e.Cancel = true;
  16:     }
  17:     else
  18:     {
  19:         _delete = false;
  20:     }
  21: }
  22:  
  23: void cd_Closed(object sender, EventArgs e)
  24: {
  25:     PeopleBrowser.Effect = null;
  26:     ConfirmDialog cd = sender as ConfirmDialog;
  27:     if (cd.DialogResult == true)
  28:     {
  29:         _delete = true;
  30:         PeopleBrowser.DeleteItem();
  31:     }
  32: }

You can try this out yourself here (requires Siliverlight 3): Sample confirm delete with DataForm.  Go ahead, I’ll wait. 

Obnoxious isn’t it :-).  Of course using Expression Blend to customize your own is highly recommended!

Summary

While there is no true modal dialog in Silverlight other than MessageBox (which isn’t XAML-customizable), these are two options that provide you with the opportunity to confirm your delete action within DataForm.  Hopefully these are helpful to get you to think at least and if someone has better implementations, please share them!  You can download the complete code for this sample here: ConfirmDeleteDataForm.zip

Hope this helps!

| Comments

It’s getting to be that time of year again…PDC!!!  For those who may not know, “PDC” is the beloved TLA for Microsoft’s Professional Developer Conference.  This is it.  The geeks conference.  If you are a bit twiddler, this is for you.  PDC is where most of the forward-looking stuff is revealed.  It is also where certain executives come out for their semi-annual keynote ;-).

Microsoft PDC logo

PDC is in their 14th year!  Amazing.  The conference, held at the Los Angeles Convention Center from 17-19 NOV (with pre-cons happening on 16-NOV), will be awesome.  Learn about new stuff, see things you haven’t even heard of yet, and network with the industry’s best.  Silverlight will have some representation there of course and you can see some hints already on the session listings:

It is going to be a great PDC for Silverlight and I will definitely be there to hang out with the developers and listen to your feedback about Silverlight and see what you are doing with it.  Follow PDC09 on Twitter or search for #pdc09 for information updates.

Join me in LA!  And if anyone wants to help me find the Kogi BBQ truck while there this time, let me know ;-)

| Comments

I came across this add-in for Visual Studio the other day that is subtle but added some productivity features to Visual Studio for me.  It’s called Tabs Studio.

NOTE: I’m not getting a complimentary license for this add-in and have already purchased my own license with my own money.  This is an unsolicited opinion.

For me Tabs Studio does two things: organize my open content better and enables me to more quickly close/manage the open tabs.  Take a look at the before after of the same content open in VS:

Visual Studio 2008 tabs normal

In the before I have all the tabs open and can only close them one at a time (i.e., can’t selectively close a tab without first activating it).  Additionally, It is shown in order of opening.  I may have MainPage.xaml somewhere along the project, but not right next to the MainPage.xaml.cs file that I also need.  On a recent project I had about 15 files open at once and hunting to find the related ones was a nuisance when you needed to be fast.  Now look at the after:

Visual Studio 2008 tabs with Tabs Studio

Same amount of tabs open, but the “related” ones are automatically grouped for me, and the bold shows which one is open.  Additionally I can selectively close the code file without first activating the tab (each tab in Tabs Studio has a close button like Firefox tabs implementation).  This is great.

What’s the best part?  It’s all XAML!  The Tabs Studio is a WPF control that you can customize to your liking by putting your own styles in the settings pane using BasedOn styling:

Tabs Studio Settings dialog

Very cool  So far this little add-in is helping me just a tad more productive and it stays out of my way!

| Comments

One of the new features to Silverlight 3 is the ability to add multi-touch capabilities to your application.  When I posed the question on Twitter, I got some responses of ideas people would use this for.  Honestly most of them could be accomplished with mouse events today and X/Y calculations.  These would be the touch applications that are pretty singular.  But I did get some multi-touch ideas that I think I’ll try to explore.  First though, let’s look at the basics of what Silverlight provides for multi-touch application development.

Hardware

Hopefully I’m stating the obvious here, but your hardware has to support multi-touch.  And I’m not talking about that fake kind.  I’m talking about hardware that announces the WM_TOUCH messages to Windows.  If you (or your customers) aren’t going to be having multi-touch hardware, then writing against this API isn’t going to help!  I’m currently using the HP TouchSmart TX2 laptop running Windows 7.  I find this to be a good machine and fairly cheap-ish with regard to how laptops are these days and with the features it provides.

The Event

The first thing to understand is how to tap into the touch events from the hardware to Silverlight.  Understanding this at the beginning of your application development can be a critical step.  The key reason for this is unlike other input events (i.e., MouseLeftButtonDown, etc.) which can be added to individual UIElements in an application, the touch event is an application-wide event. 

There is one primary event: FrameReported.  This event is what gets fired when the hardware sends the touch events to the runtime.  The Touch class is a static class for the sole reason of this FrameReported API.  To wire it up in your application you can use code like this:

   1: Touch.FrameReported += new TouchFrameEventHandler(Touch_FrameReported);

And now you have to write your event handler.

The Event Handler Arguments

Once the runtime receives a touch message, the FrameReported event fires (and will do so several times…see later here).  The arguments you get that you primarily need to concern yourself in most circumstances are the GetPrimaryTouchPoint and GetTouchPoints.

The primary touch point could be thought of as the first touch message/point that the runtime received in a current sequence.  So if your application is using single gesture touch behaviors, this is likely what you’d use.  Otherwise GetTouchPoints is going to give you all the registered touch points from the hardware reported to the runtime.

For me understanding the Move event is critical.  If you take a look and add the data to my diagnostic app below for Move, you’ll see that even simply touching your finger in one place fires constant Move commands.

What you get in a TouchPoint

Both the primary and the collection of touch points listed above will return the TouchPoint object, which contains valuable information.  Namely it is going to give you Postition, which is a point relative to the offset you provided in the GetTouchPoint call (or absolute if you pass in null).

You also get the Action of the touch.  There are three actions: Down, Move and Up.  It is important to understand the firing sequence here.  Assume a given TouchPoint, it will first report Down, then it will continue to report Move until the touch is removed, at which point Up will occur.  The key piece in the middle is Move.  This action is firing even if you aren’t moving any element.  It is essentially reporting that you have a TouchPoint that is in Down state (i.e., touched).  Move can be helpful if you are needing to move things along with the updated position of the element.

You also get the TouchDevice which contains some helpful information.  Provided via the TouchDevice is an Id value, which is a unique id provided by the operating system for the device which reported the TouchPoint.  Also provided is DirectlyOver which is the topmost UIElement the position is over at the time the touch was produced.

What about my mouse events?

Ah, good point!  In the TouchFrameEventArgs you have a method you can call which is SuspendMousePromotionUntilTouchUp.  You would want to use this if you knew *for sure* that the end user had multi-touch hardware.  This would prevent the mouse event promotion for the given touch point.  This method can only be called if the Action is Down for the TouchPoint.  Once the TouchPoints all report Up, then normal mouse event promotion would resume.

Putting it all together

For these basics, I decided just to create a quick diagnostic application that would show the registering of the TouchPoint elements, as well as identifying the primary touch point.  My application has registered the FrameReported event handler and then I’ve added some logic:

   1: public MainPage()
   2: {
   3:     InitializeComponent();
   4:     Touch.FrameReported += new TouchFrameEventHandler(Touch_FrameReported);
   5: }
   6:  
   7: void Touch_FrameReported(object sender, TouchFrameEventArgs e)
   8: {
   9:     foreach (TouchPoint tp in e.GetTouchPoints(this.Positions))
  10:     {
  11:         if (tp.Action == TouchAction.Down)
  12:         {
  13:             // do something
  14:         }
  15:     }
  16: }

The end result is that when the user touches that application surface, we add the TouchPoint to an ObservableCollection that is bound to a DataGrid to show the points currently registered and by which device.  When the user removes the touch action, they go away.

Obviously it is hard to demonstrate touch capabilities in a screenshot and it really does it no justice.  I’m going to do my best attempt here to show you a picture-in-picture view of the application running and me interacting with it via Touch.  You’ll need Silverlight to view this demonstration.

Summary

There you have it.  The basics of multi-touch in Silverlight 3.  It’s fairly simple to understand the core mechanics of the API.  What gets tricky is interacting with your application beyond just showing the points :-).  In a future post I’ll show an application that makes use of this multi-touch feature in understanding where the touch occurred in my given application and how you can find the element that was touched (even though it’s an application-wide event).  If you aren’t subscribed, please consider subscribing to my blog for regular updates for Silverlight information.

Feel free to spelunk this diagnostic app code:  MultiTouch_CS.zip (C#) or MultiTouch_VB.zip (Visual Basic).

Hope this helps!

| Comments

I got enough feedback and suggestions that I figured it would be better just to put the code up on CodePlex rather than package zips on my blog :-).  Here it is: FloatableWindow project.  The latest build I have is up there which incorporates some feedback that I’ve received.

UPDATE: If you like this idea VOTE FOR IT in the Silverlight Toolkit!

Basically the ShowDialog() API operates the same way that ChildWindow.Show() does today.  No changes there, popup is used.  But when you just want some simple MDI type windows, use Show() which will not use Popup but rather add the elements as children to your root visual.  Now the key here is defining that root.  Before you show the window you’d want to do something like this:

   1: FloatableWindow fw = new FloatableWindow();
   2: fw.Width = 200;
   3: fw.Height = 200;
   4: fw.Title = "Foobar";
   5: fw.ParentLayoutRoot = this.LayoutRoot;
   6: fw.VerticalOffset = 200;
   7: fw.HorizontalOffset = 100;
   8: fw.Show();

Notice line #5 where I specify a Panel element to add it to?  That would be required.  An ArgumentNullException is thrown if it is not provided.

Thanks for the great feedback and encouragement on this refactoring.  I hope that putting it on CodePlex provides a better home for evolution and tracking issues (I know there is an animation issue now with non-modal).