WynApse Home Page
Home    Blog    About    Contact       
Latest Article:


My Tags:
My Sponsors:






Lifetime Member:

Silverlight Intuitive Drag and Drop




Visually-Intuitive

I'll show the final canvas first ... this is what I was shooting for when I started. Getting here wasn't a direct path, so I thought I'd explain it.

I like the way this canvas works... you mouse-down on one of the rectangles and it drags up on top of the other two in what is a more 'intuitive' drag-and-drop operation than simply moving the rectangles around.

To make it more obvious what's going on, I put the ZIndex of the rectangle after it's color once you start moving them around.





Code-Intuitive

The less visual-intuitive version of the above canvas is shown below. The code for this, however, is more intuitive.

In retrospect, I realized of course that a redraw would be necessary to get the ZIndex-enforcement to take place and shuffle the rectangles properly, and we don't have a redraw on the Canvas object.

Aside from that minor difficulty, this canvas points out an interesting issue with writing to Rectangles, or even Canvases in this case, that are below others.

I thought it would be very cool to click on the yellow rectangle and have the ZIndex change on all 3, and at the same time have the text on all 3 change to reflect the ZIndex change.

I ran into a problem with the text on the lower-order ZIndexed rectangles that can be better seen if you position them close enough that the text on an upper one is overlapped by a lower rectangle and then the lower one clicked.

What you will see might be something like this:


In this example, the order from the bottom was: Blue, Yellow, then Green. I clicked on the Yellow rectangle, and got this result. I can only speculate on the reason...

It appears that when the TextBlocks are redrawn with the new text, the ZIndex is taken into consideration in some manner. If you zoom in on the Green block, the "Bl" from the Blue rectangle actually is anti-aliased as if it is against a blue background. The yellow blocks on the green rectangle don't appear to have any text at all in them, so that is confusing as well.

You can try this with the canvas shown here:




One More Canvas

I had a thought to change the text prior to the ZIndex to see if that would make a difference, and it didn't, but thought a very restricted example might be instructive as in the canvas below. In this one, no 'dragging' is done, the only mouse message responded to is MouseDown and MouseUp on the Yellow rectangle as explained:
  • MouseDown: Text is written in the yellow canvas with the ZIndex still below Green and Blue.
  • MouseUP: The ZIndex of the Yellow rectangle is set above that of the Green and Blue and text is written again.
I think this makes it pretty obvious how the ZIndex is handled and what happens when we use it:




Conclusion

As with the Silverlight Rectangles, Paths, and Line Comparison article, I think this all falls more in the category of "user beware". Knowing how the ZIndex really works will enable solutions like my first canvas to be displayed. In that one, if you investigate the Java Script, you'll see that no ZIndices were changed until the MouseMove message was handled. That caused a redraw, and I was able to avoid the issues demonstrated in the other two canvases.

In the Java Script below, the three canvas messages are blocked off and marked as such. I've included all 3 xaml files in one display block as well.

JavaScript for producing this page:

<script type="text/javascript">

//
// First Canvas:
//
var beginX;
var beginY;
var isMouseDown = false;
var fRedraw = 0;
var nElements = 3;

function onMouseDown(sender, mouseEventArgs)
{
// Ensure this object is the only one receiving mouse events.
sender.captureMouse();
fRedraw = 0;

// Set the beginning position of the mouse.
beginX = mouseEventArgs.getPosition(null).x;
beginY = mouseEventArgs.getPosition(null).y;

isMouseDown = true;
}

// Stop drag and drop operation.
function onMouseUp(sender, mouseEventArgs)
{
isMouseDown = false;

// All all objects to receive mouse events.
sender.releaseMouseCapture();
}

// Reposition object during drag and drop operation.
function onMouseMove(sender, mouseEventArgs)
{
// Determine whether the mouse button is down.
// If so, move the object.
if (isMouseDown == true)
{
// Retrieve the current position of the mouse.
var currX = mouseEventArgs.getPosition(null).x;
var currY = mouseEventArgs.getPosition(null).y;

// Reset the location of the object.
sender["Canvas.Left"] += currX - beginX;
sender["Canvas.Top"] += currY - beginY;

// Update the beginning position of the mouse.
beginX = currX;
beginY = currY;
if (fRedraw == 0)
{
var oldIndex = sender["Canvas.ZIndex"];

var mainCanvas = sender.findName("Board");
// Enumerate the children of the Canvas object.

if (mainCanvas.children.count > 0)
{
for (i = 0; i < mainCanvas.children.count; i++)
{
var child = mainCanvas.children.getItem(i);
var childZ = child["Canvas.ZIndex"];
if ((childZ >=0) && (childZ > oldIndex) && (childZ <= nElements) && (child != sender))
{
child["Canvas.ZIndex"] = childZ - 1;
var sChild = child.Name.toString();
var sText = sender.findName(sChild + "_Caption").Text.toString();
sender.findName(sChild + "_Text").Text = sText + " " + child["Canvas.ZIndex"];
}
}
}
sender["Canvas.ZIndex"] = nElements;
var sChild = sender.Name.toString();
var sText = sender.findName(sChild + "_Caption").Text.toString();
sender.findName(sChild + "_Text").Text = sText + " " + sender["Canvas.ZIndex"];
fRedraw = 1;
}
}
}


//
// Second Canvas:
//


var beginX2;
var beginY2;
var isMouseDown2 = false;
var fRedraw2 = 0;
var nElements2 = 3;

function onMouseDown2(sender, mouseEventArgs)
{

// Ensure this object is the only one receiving mouse events.
sender.captureMouse();
fRedraw2 = 0;

// Set the beginning position of the mouse.
beginX2 = mouseEventArgs.getPosition(null).x;
beginY2 = mouseEventArgs.getPosition(null).y;

isMouseDown = true;

var oldIndex = sender["Canvas.ZIndex"];

var mainCanvas = sender.findName("Board");
// Enumerate the children of the Canvas object.

if (mainCanvas.children.count > 0)
{
for (i = 0; i < mainCanvas.children.count; i++)
{
var child = mainCanvas.children.getItem(i);
var childZ = child["Canvas.ZIndex"];
if ((childZ > oldIndex) && (childZ <= nElements2) && (child != sender))
{
var sChild = child.Name.toString();
var sText = sender.findName(sChild + "_Caption").Text.toString();
sender.findName(sChild + "_Text").Text = sText + " " + (childZ - 1);
}
}
for (i = 0; i < mainCanvas.children.count; i++)
{
var child = mainCanvas.children.getItem(i);
var childZ = child["Canvas.ZIndex"];
if ((childZ > oldIndex) && (childZ <= nElements2) && (child != sender))
{
child["Canvas.ZIndex"] = childZ - 1;
}
}
}
sender["Canvas.ZIndex"] = nElements2;
var sChild = sender.Name.toString();
var sText = sender.findName(sChild + "_Caption").Text.toString();
sender.findName(sChild + "_Text").Text = sText + " " + sender["Canvas.ZIndex"];

}

// Stop drag and drop operation.
function onMouseUp2(sender, mouseEventArgs)
{
isMouseDown = false;

// All all objects to receive mouse events.
sender.releaseMouseCapture();
}

// Reposition object during drag and drop operation.
function onMouseMove2(sender, mouseEventArgs)
{
// Determine whether the mouse button is down.
// If so, move the object.
if (isMouseDown == true)
{
// Retrieve the current position of the mouse.
var currX = mouseEventArgs.getPosition(null).x;
var currY = mouseEventArgs.getPosition(null).y;

// Reset the location of the object.
sender["Canvas.Left"] += currX - beginX2;
sender["Canvas.Top"] += currY - beginY2;

// Update the beginning position of the mouse.
beginX2 = currX;
beginY2 = currY;
}
}


//
// Third Canvas:
//

function onMouseDown3(sender, mouseEventArgs)
{
sender.findName("WriteSomething").Text = "Write Something Across all three Rectangles on Mouse Down";
}

function onMouseUp3(sender, mouseEventArgs)
{
sender["Canvas.ZIndex"] = 4;
sender.findName("WriteSomethingElse").Text = "Write Something Else Across all three Rectangles on Mouse Up";
}




</script>


XAML for producing this page:

<!-- Upper Canvas -->

<Canvas
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<Canvas x:Name="Board" >
<Rectangle Canvas.Left="0" Canvas.Top="0" Width="500" Height="400" Stroke="SteelBlue" Canvas.ZIndex="-1"/>

<Canvas x:Name="YellowNote"
Canvas.Left="10" Canvas.Top="10" Width="253" Height="203"
Canvas.ZIndex="1"
Cursor="Hand"
MouseLeftButtonDown="onMouseDown"
MouseLeftButtonUp="onMouseUp"
MouseMove="onMouseMove">
<Rectangle Canvas.Left="3" Canvas.Top="3" Width="250" Height="200" Fill="#C0C0C0" />
<Rectangle Canvas.Left="0" Canvas.Top="0" Width="250" Height="200" Fill="Yellow" />
<TextBlock x:Name="YellowNote_Text" Canvas.Left="10" Canvas.Top = "10" Foreground="Black" FontSize="14" Text="Yellow" />
<TextBlock x:Name="YellowNote_Caption" Visibility="Collapsed" Text="Yellow" />
</Canvas>

<Canvas x:Name="GreenNote"
Canvas.Left="60" Canvas.Top="60" Width="253" Height="203"
Canvas.ZIndex="2"
Cursor="Hand"
MouseLeftButtonDown="onMouseDown"
MouseLeftButtonUp="onMouseUp"
MouseMove="onMouseMove">
<Rectangle Canvas.Left="3" Canvas.Top="3" Width="250" Height="200" Fill="#C0C0C0" />
<Rectangle Canvas.Left="0" Canvas.Top="0" Width="250" Height="200" Fill="Green" />
<TextBlock x:Name="GreenNote_Text" Canvas.Left="10" Canvas.Top = "10" Foreground="White" FontSize="14" Text="Green" />
<TextBlock x:Name="GreenNote_Caption" Visibility="Collapsed" Text="Green" />
</Canvas>

<Canvas x:Name="BlueNote"
Canvas.Left="110" Canvas.Top="110" Width="253" Height="203"
Canvas.ZIndex="3"
Cursor="Hand"
MouseLeftButtonDown="onMouseDown"
MouseLeftButtonUp="onMouseUp"
MouseMove="onMouseMove">
<Rectangle Canvas.Left="3" Canvas.Top="3" Width="250" Height="200" Fill="#C0C0C0" />
<Rectangle Canvas.Left="0" Canvas.Top="0" Width="250" Height="200" Fill="Blue" />
<TextBlock x:Name="BlueNote_Text" Canvas.Left="10" Canvas.Top = "10" Foreground="White" FontSize="14" Text="Blue" />
<TextBlock x:Name="BlueNote_Caption" Visibility="Collapsed" Text="Blue" />
</Canvas>

</Canvas>

</Canvas>

<!-- Middle Canvas -->

<Canvas
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<Canvas x:Name="Board" >
<Rectangle Canvas.Left="0" Canvas.Top="0" Width="500" Height="400" Stroke="SteelBlue" Canvas.ZIndex="-1"/>

<Canvas x:Name="YellowNote"
Canvas.Left="10" Canvas.Top="10" Width="253" Height="203"
Canvas.ZIndex="1"
Cursor="Hand"
MouseLeftButtonDown="onMouseDown2"
MouseLeftButtonUp="onMouseUp2"
MouseMove="onMouseMove2">
<Rectangle Canvas.Left="3" Canvas.Top="3" Width="250" Height="200" Fill="#C0C0C0" />
<Rectangle Canvas.Left="0" Canvas.Top="0" Width="250" Height="200" Fill="Yellow" />
<TextBlock x:Name="YellowNote_Text" Canvas.Left="10" Canvas.Top = "10" Foreground="Black" FontSize="14" Text="Yellow" />
<TextBlock x:Name="YellowNote_Caption" Visibility="Collapsed" Text="Yellow" />
</Canvas>

<Canvas x:Name="GreenNote"
Canvas.Left="60" Canvas.Top="60" Width="253" Height="203"
Canvas.ZIndex="2"
Cursor="Hand"
MouseLeftButtonDown="onMouseDown2"
MouseLeftButtonUp="onMouseUp2"
MouseMove="onMouseMove2">
<Rectangle Canvas.Left="3" Canvas.Top="3" Width="250" Height="200" Fill="#C0C0C0" />
<Rectangle Canvas.Left="0" Canvas.Top="0" Width="250" Height="200" Fill="Green" />
<TextBlock x:Name="GreenNote_Text" Canvas.Left="10" Canvas.Top = "10" Foreground="White" FontSize="14" Text="Green" />
<TextBlock x:Name="GreenNote_Caption" Visibility="Collapsed" Text="Green" />
</Canvas>

<Canvas x:Name="BlueNote"
Canvas.Left="110" Canvas.Top="110" Width="253" Height="203"
Canvas.ZIndex="3"
Cursor="Hand"
MouseLeftButtonDown="onMouseDown2"
MouseLeftButtonUp="onMouseUp2"
MouseMove="onMouseMove2">
<Rectangle Canvas.Left="3" Canvas.Top="3" Width="250" Height="200" Fill="#C0C0C0" />
<Rectangle Canvas.Left="0" Canvas.Top="0" Width="250" Height="200" Fill="Blue" />
<TextBlock x:Name="BlueNote_Text" Canvas.Left="10" Canvas.Top = "10" Foreground="White" FontSize="14" Text="Blue" />
<TextBlock x:Name="BlueNote_Caption" Visibility="Collapsed" Text="Blue" />
</Canvas>

</Canvas>

</Canvas>

<!-- Bottom Canvas -->

<Canvas
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<Canvas x:Name="Board" >
<Rectangle Canvas.Left="0" Canvas.Top="0" Width="500" Height="400" Stroke="SteelBlue" Canvas.ZIndex="-1"/>

<Canvas x:Name="YellowNote"
Canvas.Left="10" Canvas.Top="10" Width="253" Height="203"
Canvas.ZIndex="1"
Cursor="Hand"
MouseLeftButtonDown="onMouseDown3"
MouseLeftButtonUp="onMouseUp3">
<Rectangle Canvas.Left="3" Canvas.Top="3" Width="250" Height="200" Fill="#C0C0C0" />
<Rectangle Canvas.Left="0" Canvas.Top="0" Width="250" Height="200" Fill="Yellow" />
<TextBlock x:Name="YellowNote_Text" Canvas.Left="10" Canvas.Top = "10" Foreground="Black" FontSize="14" Text="Yellow" />
<TextBlock x:Name="YellowNote_Caption" Visibility="Collapsed" Text="Yellow" />
<TextBlock x:Name="WriteSomething" Canvas.Left="10" Canvas.Top = "140" Text="" />
<TextBlock x:Name="WriteSomethingElse" Canvas.Left="10" Canvas.Top = "160" Text="" />
</Canvas>

<Canvas x:Name="GreenNote"
Canvas.Left="60" Canvas.Top="60" Width="253" Height="203"
Canvas.ZIndex="2">
<Rectangle Canvas.Left="3" Canvas.Top="3" Width="250" Height="200" Fill="#C0C0C0" />
<Rectangle Canvas.Left="0" Canvas.Top="0" Width="250" Height="200" Fill="Green" />
<TextBlock x:Name="GreenNote_Text" Canvas.Left="10" Canvas.Top = "10" Foreground="White" FontSize="14" Text="Green" />
<TextBlock x:Name="GreenNote_Caption" Visibility="Collapsed" Text="Green" />
</Canvas>

<Canvas x:Name="BlueNote"
Canvas.Left="110" Canvas.Top="110" Width="253" Height="203"
Canvas.ZIndex="3">
<Rectangle Canvas.Left="3" Canvas.Top="3" Width="250" Height="200" Fill="#C0C0C0" />
<Rectangle Canvas.Left="0" Canvas.Top="0" Width="250" Height="200" Fill="Blue" />
<TextBlock x:Name="BlueNote_Text" Canvas.Left="10" Canvas.Top = "10" Foreground="White" FontSize="14" Text="Blue" />
<TextBlock x:Name="BlueNote_Caption" Visibility="Collapsed" Text="Blue" />
</Canvas>

</Canvas>

</Canvas>
Copyright © 2006-2017, WynApse