Thursday, July 30, 2009

WPF designer cannot render most forms

I have written a few projects in WPF now. What I don't understand is, why is the designer so fragile ? It seems as soon as I create any sort of reusable control, and use it on a form, even though the control exists in the same code base as the form, the form will no longer be able to render properly, it will report errors, which are invariably 'can't create an instance of MyCoolControl'. Of course, at run time it works fine, and the code for the control is right there, so I don't really understand what the issue is. I have talked to other people who have THEIR controls inside seperate dlls, which is apparently the recommended way to resolve this 'issue'. They still have the same error, and the way they have solved it, is by putting those dlls in the GAC.

Wait a minute. If I want to create a control inside my WPF app ( which is surely the OO way to do things, create it once and reuse it ), then I should create it in a seperate dll, and THEN put that dll in the GAC, so that the designer will work properly ? Am I the only person who thinks that is insane ?

Of course, I've not seen VS 2010, there is some possibility that this has been fixed. But, for now, it's a constant annoyance.

Tuesday, July 28, 2009

Pop unders/child windows

I am updating our website. So, in VS I open each image in my website, then I copy it to do a new screenshot in our updated UI. Then I save it from photoshop. Here's where the problem starts. VS opens a window telling me the image has been updated. I need to close this before VS becomes responsive again. Only, it's not a child window of the IDE, so I have to ALT-TAB looking for it every time, so I can close it. I know I've had other issues with popunder windows like this making other MS programs seem to freeze up. Is it that hard to set the owner of a window before you show it ? I don't know. I know it's frustrating to have to do over and over, because some basic UI rules were ignored.

Wednesday, July 22, 2009

Object Orientation in .NET ( has anyone at Microsoft heard of it ? )

It's not uncommon to be working with code and want to call an event explicitly. In this case, classes derived from the EventArgs class, have an Empty property, which returns an empty instance, useful for doing exactly that, without having to construct an object we will not use. However, while it's possible to use the 'new' keyword to override a property, doing MyMethod(this, RoutedEventArgs.Empty); returns a compiler error, as the Empty propertly returns EventArgs, not RoutedEventArgs. In other words, while RoutedEventArgs in particular represents a class where you are very likely to not examine the event arguments, you still cannot use the property, it is worthless.

This is true of ALL derived classes of EventArgs, although I can see how, for example, a mouse related event args can be assumed to contain data you need ( although this is often not true, if I handle the mouse left button click event, I don't often care about anything passed in ) The only place I can think of where this is almost sure to not be the case, is keyboard events, where usually I want to know what key was pressed. It is for this reason that I've never tried to use KeyEventArgs.Empty, that is, assuming I were to forget that the construct as a whole is useless.

In the same way when I use Bitmap.FromFile in C# in general, I need to cast the Image that is returned, to a Bitmap. This is because it's calling a base method, I guess. That makes sense, but then why not make the base method return a Bitmap, given that you can't alter a method by return type, however, if I called Image.FromFile and got back a Bitmap, I could quite happily assign the value to an Image, and it would downcast. In fact, all things being equal, it's possible that the class always returns a Bitmap, but always specifies an Image as the return type.

Yes, I am right. The Image.FromFile ultimately calls this:

internal static Image CreateImageObject(IntPtr nativeImage)
{
int type = -1;
int status = SafeNativeMethods.Gdip.GdipGetImageType
(new HandleRef(null, nativeImage), out type);
if (status != 0)
{
throw SafeNativeMethods.Gdip.StatusException(status);
}

switch (((ImageTypeEnum) type))
{
case ImageTypeEnum.Bitmap:
return Bitmap.FromGDIplus(nativeImage);
case ImageTypeEnum.Metafile:
return Metafile.FromGDIplus(nativeImage);
}

throw new ArgumentException(SR.GetString("InvalidImage"));
}

As an aside, surely this code would be prettier if the exception came from a default case, instead of just sitting underneath like that. Do they have coding standards in Redmond ? In fairness, if my suggestion would compile at all, I am pretty sure that it didn't work in early versions at least, b/c the compiler could not work out that every case had a return value. So, perhaps this code has just not been looked at in a long time.

The return type here is an Image. Bitmap.FromGDIplus looks like this:

internal static Bitmap FromGDIplus(IntPtr handle)
{
Bitmap bitmap = new Bitmap();
bitmap.SetNativeImage(handle);
return bitmap;
}
So, in a nutshell, even if I am using an Image, I get sent a Bitmap, but if I am using a Bitmap, or an Image, either way, the object is downcast to an Image for no good reason that I can see, before I get it back. No memory is saved, all that happens, is another reason for a meaningless cast.

Bitmap bm = (Bitmap) Bitmap.FromFile(@"c:\Image.jpg");

Is that really the best we can do ?

Tuesday, July 7, 2009

Working with images in WPF is not straightforward

It's taken me a while to get my head wrapped around exactly what is going on here, but there's some serious issues with image controls in WPF.  My first manifestation of all this was that I'd load a BitmapSource into an Image, and it would not be visible, the control would continue to have a width and height of 0.  If I wrote code to try to manually set sizes ( even though I shouldn't have to ), the size of my image would come back as 0.  

What happens is, images are loaded on another thread.  So, when my code asks for the image size, it's 0.  Of course, this means if I am debugging, then I introduce a delay, so the thread can run, and the size is there.  So, if you want to do anything when an image is loaded, your best bet, is to use the size changed event on the Image control.  I've found that I need to put the images inside a StackPanel, if I put them in a Grid, they are just never visible, if I use the * notation, which I always try to do, to create forms that can be resized smoothly.  

What the framework desperately needs, is an ImageLoaded event, so you can write code to run when the image loads, THEN tell it to start loading.  I don't understand how this was missed, I'd have thought that being able to load an image, then do something based on the size of the image, would be pretty common in a framework whose main claim to fame is a freeform user interface.

Thursday, July 2, 2009

Update : hotfix for bugs in XAML designer in VS 2008

With thanks to Mark for the link, http://code.msdn.microsoft.com/KB963035 is the hotfix for the issue I reported previously, where the VS2008 designer will freeze if you edit XAML. I remain confused how such a bug escaped testing, but at least there's a fix. I don't have it installed yet, but others tell me it's helped them.

Wednesday, July 1, 2009

Breaking Visual Studio is too easy

My first real WPF app started out fine, but over time, I found that I could build it perhaps once, then I'd get an out of memory exception and have to restart the IDE, or sometimes even reboot. You can imagine what a pain this was. I did some research and found that this is quite a common issue for a lot of people. There are other issues, for example, someone I know tells me that for him the linker crashes with an internal error inside the "IncrBuildImage" function, every second build. He's building native code. I don't know the answer to his issue, but I know how I solved mine.

The issue is that the compiler often can't deal with a WPF app that has a lot of resources in it ( my exe was 32 MB which included a lot of UI elements as PNGs ). There's two solutions here:

1 - make your UI elements XAML. This just makes sense, they take up less space, and scale to any size. Expression Design is actually awesome at taking Adobe Illustrator and other formats and turning them in to XAML. This is the approach I am taking going forward

2 - put all your resources in a dll. If you're showing big images, as I invariably am given the apps I write, then you may not want or be able to convert them to XAML. So, put them in a dll, which you never change, and therefore do not have to build more than once.

I would prefer not to have my images in a resource dll, but it's made me a lot more productive. If they fix this bug in VS2010, I may go back to how it was, but certainly this works, and it is an effective workaround for yet another Visual Studio bug.

I am actually travelling to the US for a couple of weeks starting tomorrow, so my post frequency may slow down, although I do have at least 10 other .NET issues bookmarked to write about, so with some luck I may manage to keep up my current post frequency of a couple every now and then. Doesn't sound too challenging, but if this post is two weeks old and it's on top, that's my excuse, and I'll be posting again for sure when I get back.