Wednesday, November 19, 2008

Visual Studio 2008's bug in it's XAML editor bugged me all morning

All I got to say is "AAAAHHH!"...

I spent the morning trying to figure out why Intellisense fails to work in my XAML files. Life was great, then one day it stopped working. I couldn't figure out why. Googling for solutions came up with nothing.

So, I decided to create a blank XAML file in my project. Guess what? Intellisense worked there. So, I went through starting to recreate my "bad" XAML file. As soon as I added a namespace reference to my own assembly, it broke. In the code snippet below, you'll see the offending line. It's the xmlns:local. Remove that line, Intellisense works, add it and Intellisense breaks. Great!



<Window x:Class="MyProject.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyProject">



Now that I knew it was related to that line, a much more targeted google brought up this one Microsoft forum where the issue was discussed, recognized as a bug by MS, and supposed will be fixed in the next Service Pack. Problem was, at the time of writing, the next SP was to be SP1. I've got SP1, but the bug still persists.

So, in light of the stupid bug, this is the workaround I'm using. It's not perfect, but if you use a reference to your local assembly only for a model-view, you can push your model-view off into a resource file then link via a shared dictionary to your actual UI.

SharedResources.xaml:



<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:MyProject"
>
<!-- Your local resources go here.. oh, and Intellisense is broken when editing this file -->
</ResourceDictionary>


And now the actual window...



<Window x:Class="MyProjects.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="SharedResources.xaml"/>
<ResourceDictionary>
<!-- Any local resources -->
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>

<!-- Your contents -->
</Window>


Sometimes you make coding decisions just because you like your IDE too much to give up it's tools...

Monday, November 3, 2008

WPF & Multithread - Part 2 and creating multiple windows on different messaging threads

In my previous post I talked about getting input from a user while running on a business thread. You maybe wondering what happens if I choose to just always create a new STA thread rather than check to see if the calling thread is already on an STA thread. After all, that's less code.

Well, that's what I originally did, until I ran into a problem. You see, it all comes down to calling the Thread.Join call. This call blocks the calling thread. So, if the calling thread is the UI thread, you've just blocked it! Oops.. there goes the message pumping for that thread. So, say you have a timer on your main window. Well, suddenly it comes to a stop. In my case, I had a custom NativeWindow class that listens for keystrokes across the application to detect incoming barcode values from a barcode scanner. For my application it is essential the WndProc override of my NativeWindow always gets called. This is because I use the Raw Input API to filter keyboard input searching for barcode values. However, the Raw Input API stops all WM_KEYxx calls from being generated. The only way any of my WPF windows will get a message (and hence keystrokes) is if I manually send the WM_KEYxx messages. So, as you can see, it is essential to the application that the NativeWindow.WndProc method is always called.

But as soon as I pop up my new WPF window to ask the user a question, they can no longer type. That's because the new window is running on the newly created STA thread and the original UI thread (and the one running the NativeWindow.WndProc) is now blocked! Users don't need to type, do they?

So, in my original post I showed a simple way to deal with this. Just check the calling thread and see if it is a UI thread. If so, show the Dialog box on that thread and you're good to go.

However, another option that also works is to create my NativeWindow on a different thread. The key is to call at the end System.Windows.Forms.Application.Run(). This method basically runs the old fashion message loop.. remember that one?



while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}


Of course, the reason I choose not to do this method was it was just too much work! First of all, now I need to worry about multiple message loops, and more cross thread issues. Secondly, an Application.Current.Shutdown() call from my WPF window doesn't shutdown the application. That's because you need to somehow communicate to the newly created window to shutdown it's thread. So, more work...

Anyway, here's a simple example of creating a new window on a different thread, so the message loop is on a different thread. I am not saying this is the way to do things, but I wrote about it because it was a good find and maybe used later..




public void Startup ()
{
Thread NewThread = new Thread(new ThreadStart(CreateWindow));
NewThread.SetApartmentState(ApartmentState.STA);
NewThread.Start();
}

private void CreateWindow()
{
// Create a new native window that will be hidden.
CreateParams cp = new CreateParams();
cp.Caption = "MyWindow";
cp.ClassName = null;
cp.Style = 0x08000000 | 0x20000000;
cp.Height = 500;
cp.Width = 500;

this.CreateHandle(cp);
CreateRegistration();

// Here is the key! Application.Run encapsulates the old standard message loop.
Application.Run();
}

Multithreading and WPF Windows

I recently had an interesting problem come up with UI threads in .NET applications and how input is processed. Here's the basic rundown...

A user initiates an event in the UI on Thread 1

The UI makes a call to some business layer to process the request. Note, this MAY or MAY NOT continue to execute on the UI thread.

The business logic needs more information before it can proceed. Nicely separated, the business thread raises an event called GetAdditionalInfo. Now, the application can either provide the information directly back to to the business logic or it may need to ask the user.

Now, here's where things get "interesting". If the business logic is running on a different thread, you've got a problem. You can't simply create a new WPF window to ask the user for the information. If you try, you'll get the following error message:

System.InvalidOperationException: The calling thread must be STA, because many UI components require this.

Well, what are you to do? A few options come up.

One option is to put a message onto the dispatch thread for the current window. While this method will definitely get your message across, you have a bit of a problem. That is, the business logic thread will continue to execute Problem is, you need to hold up the business logic thread until the user has responded to the question.

The trick lies in spawning off a new thread, creating the WPF window in that new thread, and block the business logic thread until the UI finishes. Of course, if the business logic thread is already a UI thread, this isn't needed and you can just do a ShowDialog directly. Code below...



private static void ShowWPFDialog(object arg)
{
GetAdditionalInformationWPFWindow myWindow = new GetAdditionalInformationWPFWindow();

// ShowDialog will block the calling thread..
myWindow.ShowDialog();

// Presumably at this point you have the data required from the UI... So you could set it in the arguments..
((BusinessRequestEventArgs)args).MyResult = myWindow.BusinessLogicResult;
}

private static void GetAdditionalInformation(object sender, BusinessRequestEventArgs e)
{
// If the current thread is already an STA thread we can just run on this thread.
if (Thread.CurrentThread.ApartmentState == ApartmentState.STA)
RetrieveSecondaryLogon(arg);
else
{
Thread _UIThread;
_UIThread = new Thread(new ParameterizedThreadStart(RetrieveSecondaryLogon));
_UIThread.SetApartmentState(ApartmentState.STA);
_UIThread.Start(arg);
// Block the caller until the UI thread ends..
_UIThread.Join();
}
}

Thursday, October 30, 2008

RoutedEvents to Commands

Microsoft started down a great road by introducing Commanding with WPF. However, in my opinion they didn't go far enough. While it's great that some UI elements like Buttons, Menus, etc. support sending a Command when activated, there are many other places in UI design that an action taken implies a command. The most common example I can think of is when the SelectedItem value changes in a Listbox or Combobox. Perhaps you want to either display details about a selected listbox item. Maybe you want to take action if the user double-clicks the list item. Maybe you want to immediately do some action, like a user chooses a value from a ComboBox and your ready to move forward. (I won't go into whether this is really good UI design).

Regardless, my point is, there are lots of things exposed via RoutedEvents that have no command interface, but it sure would be nice to have a command instead of a routed command.

One great thing about WPF is the extensibility. Using the Attached Behavior pattern (by John Gossman) we can create a class that will allow us to add command patterns onto UIElement for any routed command. The code is at the end of this post.

Some interesting things I learned while making this class and then trying to use it. One, XAML is good, but it's got a long way to go to catch up to the more mature .NET languages, like C#. A difficulty in XAML is the lack of generic support, so you need to do little things like my creation of the RoutedEventCommandBindingCollection class, even though it is an empty class, it creates a concrete class of the generic ObservableCollection<>.

The fact that attached property instances are not separately initialized also was a problem. For example, it would be great to initialize each attached property to be an empty list. However, we can't do this. So instead, we need to do the initialization in the XAML, as seen in the code example below. If you exclude the RoutedEventCommandBindingCollection wrapping, you get a NULL exception because the attached property EventCommandBinding (which is a list) hasn't been initialized to an empty list.


Using the class in XAML:



<UWPath:RoutedEventCommandProxy.EventCommandBinding>
<UWPath:RoutedEventCommandBindingCollection>
<UWPath:RoutedEventCommandBinding Event="UIElement.MouseUp" Command="{StaticResource MouseWasClicked}"/>
</UWPath:RoutedEventCommandBindingCollection>
</UWPath:RoutedEventCommandProxy.EventCommandBinding>



The source code in C#:



public class RoutedEventCommandProxy
{
// Fun, this will keep track of all the bindings!
private static Dictionary<UIElement, RoutedEventCommandBindingCollection> handlerTable =
new Dictionary<UIElement, RoutedEventCommandBindingCollection>();

public static readonly DependencyProperty EventCommandBindingProperty =
DependencyProperty.RegisterAttached("EventCommandBinding",
typeof(RoutedEventCommandBindingCollection),
typeof(RoutedEventCommandProxy),
new FrameworkPropertyMetadata(null, new PropertyChangedCallback(PropertyChanged)));

public static void SetEventCommandBinding(UIElement element, RoutedEventCommandBindingCollection value)
{
element.SetValue(EventCommandBindingProperty, value);
}
public static RoutedEventCommandBindingCollection GetEventCommandBinding(UIElement element)
{
return (RoutedEventCommandBindingCollection)element.GetValue(EventCommandBindingProperty);
}

private static void PropertyChanged (DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
UIElement element = sender as UIElement;

// Remove any old stuff..
if (handlerTable.ContainsKey(element))
handlerTable.Remove(element);

RoutedEventCommandBindingCollection OldMappings = (RoutedEventCommandBindingCollection)args.OldValue;
if (OldMappings != null)
{
foreach (RoutedEventCommandBinding mapping in OldMappings)
{
if (mapping.Event != null)
element.RemoveHandler(mapping.Event,new RoutedEventHandler(Handler));
}
}

// Add the new stuff
RoutedEventCommandBindingCollection NewMappings = (RoutedEventCommandBindingCollection)args.NewValue;
if (NewMappings != null)
{
handlerTable.Add(element, NewMappings);
foreach (RoutedEventCommandBinding mapping in NewMappings)
{
if (mapping.Event != null && mapping.Command != null)
element.AddHandler(mapping.Event, new RoutedEventHandler(Handler));
}
}

}

private static void Handler (object sender, RoutedEventArgs e)
{
UIElement element = sender as UIElement;
if (handlerTable.ContainsKey(element))
{
RoutedEventCommandBindingCollection mappings = handlerTable[element];
foreach (RoutedEventCommandBinding mapping in mappings)
{
if (e.RoutedEvent == mapping.Event)
{
mapping.Command.Execute(e);
}
}
}
}
}

public class RoutedEventCommandBindingCollection : ObservableCollection<RoutedEventCommandBinding>
{
}

public class RoutedEventCommandBinding
{
public RoutedEvent Event { get; set; }
public ICommand Command { get; set; }
}

WPF and Focus

So, Control focus in WPF just frustrates me sometimes. It should be simple. Control.Focus(). But things are never as they seem. Take this code for example. It simply hides a panel asking for an ID and the presents a panel asking for a Pin. With the myPinPad variable is an instance of a custom control (inherited from UserControl) with nice buttons for a pin pad and a text field to type optionally type in a pin.



private void ShowPinPad ()
{
IDBadgePanel.Visibility = Visibility.Collapsed;
PinPanel.Visibility = Visibility.Visible;
myPinPad.Focus();
}


The PinPad custom control contains an override of the OnGotFocus method as shown below. The PWD variable is a PasswordBox control that will display the pin. Now, when the PinPad control gets focus, we want the PasswordBox to get focus so a person can just start typing.



protected override void OnGotFocus(RoutedEventArgs e)
{
base.OnGotFocus(e);
PWD.Focus();
}


Anyway, this doesn't work the first time around! Why not? Well, after some investigation it is revealed that while PWD.IsInitialized is true, PWD.IsVisible is false. Of course, call ShowPinPad again later on and it works. This time IsVisible is set to true.

So, what to do? Well, I think the reason it isn't visible is that despite the status of being Initialized, it really isn't yet. Since we just made the panel containing the control visible, perhaps the render engine hasn't had time to make the children (and hence the PWD control) visible yet.

One trick is to wait a bit before sending the focus. And by wait, I mean let all the other initialization stuff finish first on the thread. This could be done with a DispatchTimer, but an even easier trick is the following:



protected override void OnGotFocus(RoutedEventArgs e)
{
base.OnGotFocus(e);
this.Dispatcher.BeginInvoke((Action)delegate { PWD.Focus(); },
System.Windows.Threading.DispatcherPriority.Background);
}


With this trick, we create an anonymous delegate and schedule it for execution at the lowest possible priority. So, hopefully everything else will get initialized first. I've tried this with my app and it works.

Thursday, October 23, 2008

Fun with SQL transactions, ADO.NETand how ExecuteScalar can bite you.

Today I wanted to create a section of code that grouped a bunch of stored procedure (SP) calls into one transaction. If any of these stored procedures failed, I want to rollback the entire transaction. It basically went something like this:

Call SP:CreateCase
Call SP:LinkIdentifierToCase
Call SP:CreatePatient
Call SP:LinkPatientToCase

Ok, first thing I tried was the .NET 2.0 TransactionScope. I won't go into details here, there are plenty of sites online how to use it. Anyway, after some digging I found that TransactionScope only works with MSDTC service enabled on the SQL server when you are running SQL 2000! Ahhh.. That's a bit heavy since it's not distributed by any means.

So, I went back to look at the ASP.NET 1.x stuff, which is the SqlConnection.BeginTransaction method. OK, looks good on the surface.. but what's it really doing? Well, I took a look at SQL profiler to find out.. And the answer is... drum roll please... Simple sending T-SQL commands BEGIN TRANSACTION, COMMIT, and ROLLBACK.

Well, that's not too bad, at least I understand it. However, bigger issues came up when your SPs have transactions in them. See, while SQL Server claims to support nested transactions, it really doesn't. For example, what would you expect this to do:



begin transaction trans1
select @@trancount
begin transaction trans2
select @@trancount
rollback transaction trans2
select @@trancount
commit transaction trans1


I would expect it to roll back the entire transaction because trans2 failed. However, commit transaction trans1 shouldn't throw an error. Guess what, as soon as rollback is executed, all nested layers are rolled back. Instead, it should nicely fall out. OK, trans2 failed, one nested layer to go. When we see another commit or rollback, we know to rollback the entire thing. Anyway, this makes things "interesting"...

What ends up happening just isn't what you expect. So, you just need to be prepared for stuff. Luckily, it seems generally ADO.NET can handle this for you. I made a simple SP that either happily completes with a COMMIT or ends with a ROLLBACK. It is:



CREATE Procedure TestProc (@DoError int)
AS
BEGIN TRAN
insert into TestTable (Name) VALUES ('Test')
if (@DoError=0)
COMMIT
else
ROLLBACK
GO


Then I created my test code:



SqlConnection conn = new SqlConnection(ConnectionString);
conn.Open();
SqlTransaction tran = conn.BeginTransaction();
try
{
SqlCommand cmd = new SqlCommand("exec TestProc 0", conn);
cmd.Transaction = tran;
cmd.ExecuteNonQuery();

cmd = new SqlCommand("exec TestProc 1", conn);
cmd.Transaction = tran;
cmd.ExecuteNonQuery();

tran.Commit();
}
catch (Exception)
{
tran.Rollback();
}
conn.Close();


Here's the output of SQL profiler:



As I would expect, while the first call the SP succeeded, the second one failed, and all the "test" table should be empty. In fact, it was. Luckily for us, ADO.NET executes a IF @@TRANCOUNT > 0 after executing each statement. This allows it to know when to throw an exception if a ROLLBACK occurs in the T-SQL, which I'm catching in the try/catch block. However, I still call tran.RollBack just to ensure the exception wasn't caused by something else, even maybe an error message (but not rollback!) from the SP itself. And look, ADO.NET is smart enough to check if the @@TRANCOUNT is great than zero before calling ROLLBACK. I can't say it's that smart when you call trans.Commit, but you should never be calling Commit if you get an exception.

So, I thought my work was done, until I found another curious issue. It seems that ExecuteScalar does not throw an exception even if a rollback occurred within the SP or an error was generated by the SP. This obviously causes a problem in my book! There is a nice forum discussion about this on MSDN.

So, conclusion. Don't blindly use BeginTransaction, especially if you have stored procedures with transactions within them. Secondly, if you want to capture any sort of error from the SQL server, don't use ExecuteScalar.

Wednesday, October 22, 2008

Storing Information Per Thread

I recently ran across a situation where I wanted to store information per Thread. After doing some research I ran across the ThreadStaticAttribute class. You apply this attribute to a static field and the value for the variable is unique for each thread. Also note that a default value is useless since it will only be initialized once and the following threads will just have a null value. So, it is best to apply this attribute to a private field and have a public property that can initialize if needed.



[ThreadStatic]
private static string myThreadValue;

public static string MyThreadValue
{
get
{
if (myThreadValue == null)
myThreadValue = "New value";
return myThreadValue;
}
}


There are other methods to store data per thread. One is SetData / GetData methods on the class System.Runtime.Remoting.Messaging.CallContext. This method allows you to specify a named variable and a value. The reason I don't like this approach is that it doesn't allow you to strongly type the data since the SetData / GetDat use a Object parameter.

Finally, the Thread.AllocateDataSlot method allows you to create a "storage slot" and use the Thread.SetData and Thread.GetData to you to store information. The reason I don't like this approach is the same as mentioned above about the lack of strong typing. Secondly, this method is is slower than the ThreadStaticAttribute.