(1 item) |
|
(1 item) |
|
(5 items) |
|
(1 item) |
|
(1 item) |
|
(2 items) |
|
(2 items) |
|
(4 items) |
|
(1 item) |
|
(6 items) |
|
(2 items) |
|
(4 items) |
|
(1 item) |
|
(4 items) |
|
(2 items) |
|
(1 item) |
|
(1 item) |
|
(1 item) |
|
(1 item) |
|
(1 item) |
|
(1 item) |
|
(1 item) |
|
(1 item) |
|
(2 items) |
|
(2 items) |
|
(5 items) |
|
(3 items) |
|
(1 item) |
|
(1 item) |
|
(1 item) |
|
(3 items) |
|
(1 item) |
|
(1 item) |
|
(2 items) |
|
(8 items) |
|
(2 items) |
|
(7 items) |
|
(2 items) |
|
(2 items) |
|
(1 item) |
|
(2 items) |
|
(1 item) |
|
(2 items) |
|
(4 items) |
|
(1 item) |
|
(5 items) |
|
(1 item) |
|
(3 items) |
|
(2 items) |
|
(2 items) |
|
(8 items) |
|
(7 items) |
|
(3 items) |
|
(7 items) |
|
(6 items) |
|
(1 item) |
|
(2 items) |
|
(5 items) |
|
(5 items) |
|
(7 items) |
|
(3 items) |
|
(7 items) |
|
(16 items) |
|
(10 items) |
|
(27 items) |
|
(15 items) |
|
(15 items) |
|
(13 items) |
|
(16 items) |
|
(15 items) |
There was a recent discussion on the Avalon newsgroup about drawing with XOR in Avalon. (In fact the scope was somewhat broader - the original question was whether WinFX was going to expose all the functionality available under Win32. XOR in Avalon was given as a specific example, because a lot of people got annoyed about the fact it is not supported in GDI+ on the current versions of .NET.)
In case you're not familiar with it, XOR drawing is a popular technique for reversible drawing operations. Specifically, if you've drawn something using XOR, it's possible to 'undraw' it again by simply repeating the exact same drawing operation. This is a useful property if you want to draw some kind of temporary overlay on top of something already on screen. XOR became a popular technique for drawing 'rubber band' selection outlines. (I.e., rectangles that you can drag out with the mouse. They are sometimes known as 'rubber band' outlines because you can change their size - stretch them - with the mouse.)
Although a popular technique, XOR drawing has some shortcomings. Rather than enumerating them here, I'll just point you to an article I wrote a few years ago for Reach magazine describing the problems with XOR, and the alternatives available with .NET and GDI+.
Avalon doesn't currently support XOR drawing. In fact it really wouldn't make much sense. XOR drawing
starts from the fundamental assumption that you are drawing pixels into a frame buffer. But in Avalon, you're
a long way removed from the frame buffer. There's one there somewhere in the guts of the graphics card, but
the primitives you get to work with are rather higher level. And with a composition-based user interface, XOR
drawing is a whole lot less useful. For example, what would it mean to XOR something onto a Canvas
which was partially occluded by some other visual element that was higher in the Z order, but which was partially
transparent? It's possible to come up with a reasonable answer as to what should happen in such cases, but
you completely lose the one benefit XOR offers: reversability.
But this non-support of XOR is a Good Thing. It means that developers will have to use the superior alternative that Avalon offers!
There is no need for XOR. At least, not if your goal is to do the kinds of things that XOR was typically
used for in Win32. (It was used mostly for mouse drag operations.) If you want to draw a 'rubber
band' selection outline in Avalon, it's actually a whole lot simpler than using XOR: just bung a rectangle into the
visual tree! To undraw it, take it back out again. Or, even simpler, leave it in the tree permanently, and just
toggle its Visibility
property to show and hide it. Here is some suitable markup for a drag
rectangle:
<Canvas ID="mainPanel" DockPanel.Dock="Fill"> ... Put any other UI you like here ... <Rectangle ID="dragRect" Visibility="Hidden" Stroke="Blue" StrokeThickness="2pt" Fill="Navy" /> <Canvas>
Note that this <Rectangle>
element has initially been set to Visibility="Hidden"
.
This is because when the application starts up, you typically don't want a drag rectangle to be shown.
Then all you need to do are add some mouse event handlers. In the MouseLeftButtonDown
event,
handler make the rectangle visible, note down the initial mouse position, and set a flag to indicate that you're dragging.
In the MouseLeftButtonUp
handler, make it invisible again and clear the dragging flag. And in the
MouseMove
handler, update the size and position of the rectangle. That last one is the only
remotely tricky one - because the rectangle's Width
and Height
properties must
be positive, there is some mildly tedious work to be done to make sure you always position the rectangle
appropriately. Here's one way. (There may well be more elegant ways, but this does the trick.)
private void OnMouseMove(object sender, MouseEventArgs e) { if (dragInProgress) { Point p = e.GetPosition(mainPanel); double w = p.X - startPoint.X; double h = p.Y - startPoint.Y; double x = startPoint.X; double y = startPoint.Y; if (w < 0) { x = p.X; w = -w; } if (h < 0) { y = p.Y; h = -h; } Canvas.SetLeft(dragRect, new Length(x)); Canvas.SetTop(dragRect, new Length(y)); dragRect.Width = new Length(w); dragRect.Height = new Length(h); } }
You can download a full example from here. (For those of you who find this via a web search a long time after I wrote it, bear in mind that this is designed to work with the PDC build of Longhorn, i.e. Build 4051.) When running, it should look like the picture to the right. It is not the simplest possible illustration of the technique. (Sorry! I got carried away.) It has a couple of extra features. First, there is a slider control that allows the opacity of the drag rectangle's fill to be set. In the picture here, it has been made partially transparent, as you can see. (The drag rectangle is the blue box the covers the text, the polygon, and part of the ellipse.) There's also a checkbox that lets you leave the rectangle visible after letting go of the mouse. (That was mainly to make getting a screenshot easier!) And finally, just to show that it can be done, one of the elements in the main window area is above the drag rectangle in the Z order. This means it will always be visible above the drag rectangle even if you choose to make it completely opaque.
The drag rectangle is defined as a markup element exactly as shown above. So if you want to modify its appearance
(e.g. give it a more interesting fill than a solid colour) then that's easily done. You could even locate the ubiquitous .wmv
file that was used in all the Avalon demos at the PDC. :-)
Note that this just shows the basic technique: using elements in the visual tree for overlays such as drag rectangles.
Nothing happens when you let go of the mouse. (So if you are expecting to see the objects in the window be selected
somehow, lower your expectations and then try again.) Also, this may not be how things will be done in the long term.
The PDC build of Avalon has an intriguing class called AnnotationPanel
which suggests that there might be
specific support for adding overlays. However, this class is documented as "Not recomended for use at this time.
Implementation in process." So I guess we have to wait until Beta 1 to find out how that's going to work.