Tuesday, January 19, 2010

Figured it out

So the solution involved "correctly" overriding both Measure and Arrange. I have to make sure I call Measure() and Arrange() on all of the children in the Adorner to make sure that I report everything correctly. Note that DesiredSize isn't valid unless you call Measure() on an object.

MeasureOverride()?!

So for whatever reason, the ResizingAdorner example is capable of getting away with this:


protected override Size MeasureOverride(Size constraint)
{
return base.MeasureOverride(constraint);
}


However, when I tried the example listed from the previous post, it does NOT work if you just call the base MeasureOverride(). Why that is, exactly, I have no damn clue yet. But it's annoying as hell. So I'm realizing the big problem is that I haven't done this measuring bit properly, and that's why I get a size of 0 available to be when it gets to the ArrangeOverride. Hopefully I'll be able to put my code back to the way it was and see what happens!

Good article?

Looks like this may be similar to what I'm looking for:

WPF Tutorial -- A Visual Collection

Interesting quote:

"and we can't use any of the normal controls that do (Panel, ContentPresenter, etc...), because only Adorners can be placed on an AdornerLayer."

Does this mean I can't use my template at all on the Adorner layer? How come MS was able to put Rects on it? Shapes aren't controls, I guess... but I've also tried adding Lines and Ellipses and they don't show in my VisualCollection either! ARGH!

I've now read that entire tutorial, and I still have no idea what's going on. It's using a ContentPresenter instead of just the VisualCollection. I can't get the Adorner to show anything, seemingly, unless I put something in OnRender. What's going ON?! Going to simplify my whole project and see what I can find.

Not quite yet...

Added the following two overrides to my Adorner, but still nothing showing up:


protected override int VisualChildrenCount { get { return visualChildren.Count; } }
protected override Visual GetVisualChild(int index) { return visualChildren[index]; }


Seems if I override ArrangeOverride, finalSize is equal to {0, 0}. That's probably not good. Must be that it doesn't know how big my Adorner is supposed to be?

Why the EFF isn't this working?! I'm just getting a freakin' black canvas. I'm even trying to add an Ellipse() now to the VisualCollection, but it's not working. The override calls are being made, and the number of children is correct, just nothing seems to be showing up when the Adorner is supposed to be rendering. The example doesn't override OnRender()... so I'm guessing I shouldn't either...

Templated Adorners

Trying to add an adorner over an image containing multiple moveable "Thumb" templates that'll allow me to have them resize properly over the image. Sure isn't working.

I'm following the MS example of "resizingadorner" fairly closely to get the extensibility. Since I'm using a template, I can't really override the OnRender like most other Adorner examples seem to try, because I don't want to have to draw the items manually myself. I'd rather they be pulled from the template I've done up.

I'm making the call to Add on the VisualCollection, but nothing shows up in the Adorner. I've yet to override the other VisualCollection functions mentioned in the example, so I'll see where that gets me.

Friday, January 15, 2010

WPF Official Image Interop

I got some ideas from here. I ended up solving the problem by creating a new bitmap source each time I received a callback. This seems pretty ridiculous and wasteful, but it was the only way I could get the image to redraw. Note that I couldn't put it inside my callback, because that would have the callback thread doing work with managed variables. I don't get why it raises an exception, because within the callback I do a Marshal.Copy between my unmanaged image data and a managed array, but hey, at least it's working. Does anybody else feel like there must be a better way to do this than to create a new managed object every frame?!

InteropBitmap

I just tried placing BitmapSource.Create() into my callback function. Sure as hell didn't work. Got this:

An unhandled exception of type 'System.Reflection.TargetInvocationException' occurred in mscorlib.dll

Additional information: Exception has been thrown by the target of an invocation.

... Thanks Microsoft! This WPF is super easy to use... ahem...

Reading around more. Looks like InteropBitmap may be a better way to do things.

InteropBitmap Link 1

That link states I can call Invalidate() on the "underlying bitmap" rather than on the Image. BitmapSource doesn't seem to have an Invalidate() call. Still a black image.

Update: The previous crash was so amazing it created a process I can't kill without rebooting. I also can't connect to the camera again until I end that process. Awesome.

InvalidateVisual()

WPF Image Processing told me to InvalidateVisual(). Put it in the GUI callback. Didn't work. Still black.

GUI Updating

Within my UpdateGUI() delegate (which seems to be getting called, and is supposed to update the GUI via the threading model I read about on the MSDN), I try setting the image1.Source to the camImage again (even though it's already done). No dice. Call UpdateLayout() to try to "refresh" the image. Nothing.

The Byte[] buffer is being written to properly, it just doesn't seem to be properly reflected in the BitmapSource after I do the copy, or the Image isn't getting properly updated by the BitmapSource.

Displaying a camera image in WPF

I admit it, I cheated. I've already been working on this problem for a while. Just going to describe the issues I'm running into as they happen.

I'm trying to display a camera image (which I obtain through an unmanaged code callback -- that was a whole other problem). It's going to be a WPF application. I started out trying to fill in a Bitmap type. After doing some online research and trying to set an Image.Source equal to the Bitmap, it looked like that wasn't the way things worked in WPF. WPF seems to use all sorts of types like BitmapSource, BitmapFrame, etc. Now I'm trying again using BitmapSource.

Here's my callback code:
      Marshal.Copy(
pPixelBuffer->pData,
imageData,
0,
pPixelBuffer->nPitch * pPixelBuffer->nHeight
);
Here, the pixel buffer is a pointer to a custom structure containing pData (the actual image data byte array), the width, and height. This copies from my unmanaged memory to managed memory (imageData is a Byte[] array). I have already assigned an image to have its source as a BitmapSource which was .Create()-ed using the imageData byte array. So why do I see a black image when I run the application?