Since Silverlight is known as the Ajax killer and is closer to desktop applications than JavaScript, the drag-and-drop effect is naturally achieved.
Layout container selection:
Silverlight provides three layout containers: canvas, grid, and stackpanel to meet various requirements. In my personal habit, grid is used for frame layout, while stackpanel is used for self-organizing specific content, while canvas is used in some specific occasions, such as the UI of the typing game.
On the one hand, GRID provides two degrees of freedom from the perspective of adaptive browser size. stackpanel provides one degree of freedom, while canvas does not, in this way, the browser cannot automatically adapt to the size change. On the other hand, grid and stackpanel can both directly specify the coordinates for layout, while canvas needs to specify the coordinates, which is certainly troublesome to maintain; third, stackpanel is the only layout container that can automatically adjust the positions of other internal controls by adding or deleting internal controls.
Therefore, the final decision is: Use the grid for external layout, set columndefinition for each column, and then add a stackpanel for each column as a single column container:
<UC: containergrid. columndefinitions>
<Columndefinition> </columndefinition>
<Columndefinition> </columndefinition>
<Columndefinition> </columndefinition>
</UC: containergrid. columndefinitions>
<UC: containerpanel grid. Column = "0" X: Name = "leftpanel">
</UC: containerpanel>
<UC: containerpanel grid. Column = "1" X: Name = "centerpanel">
</UC: containerpanel>
<UC: containerpanel grid. Column = "2" X: Name = "rightpanel">
</UC: containerpanel> containergrid and containerpanel inherit from grid and panel respectively. They mainly add several attributes that are convenient for future query and expansion.
Drag controls:
The drag-and-drop control can inherit from any control. Here, usercontrol is used.
Public partial class dragablegrid: usercontrol for dragablegrid, the main events are three: mouseleftbuttondown (left-click), mouseleftbuttonup (left-click lift), and mousemove (left-click Move ). Mouseleftbuttondown indicates the start of dragging. mouseleftbuttonup indicates that the dragging is complete, while mousemove indicates that the dragging process is triggered. In addition, the mouseleave event also serves as a mouseleftbuttonup event when the mouse moves beyond the control's movable range. Therefore, you need to add their processing logic to the constructor:
This. mouseleftbuttondown + = new mousebuttoneventhandler (dragablegrid_mouseleftbuttondown );
This. mouseleftbuttonup + = new mousebuttoneventhandler (dragablegrid_mouseleftbuttonup );
This. mousemove + = new mouseeventhandler (dragablegrid_mousemove );
This. mouseleave + = new mouseeventhandler (dragablegrid_mouseleave); left click (drag to start ):
Void dragablegrid_mouseleftbuttondown (Object sender, mousebuttoneventargs E)
{
// Start dragging
Isdraging = true;
// Start position of the mouse (inside the control)
_ Beginpoint = E. getposition (this );
// Position of the mouse relative to the grid
Point marginpoint = E. getposition (_ parentgrid );
Containerpanel parentpanel = This. Parent as containerpanel;
Shadowgrid = new shadowgrid (this, parentpanel );
// Set the initial margin.
Thickness beginmargin = New thickness (marginpoint. x-_ beginpoint. x, marginpoint. y-_ beginpoint. y, _ parentgrid. actualwidth-this. actualwidth-marginpoint. X + _ beginpoint. x, _ parentgrid. actualheight-this. actualheight-marginpoint. Y + _ beginpoint. Y );
(This. Parent as panel). Children. Remove (this );
If (this. Parent = NULL)
{
_ Parentgrid. Children. Add (this );
}
This. setvalue (grid. columnspanproperty, _ parentgrid. panelcount );
This. Margin = beginmargin;
}
First, set the isdraging flag, and then obtain the cursor position relative to the upper left corner of the control and the displacement relative to the upper left corner of the containergrid to obtain the margin value of the drag-and-drop control relative to the containergrid. Note that the movement of the mouse relative to the upper left corner of the control remains unchanged during the drag process, so it is stored as a private variable for the Drag Control. Then, remove dragablegrid from the parent panel and add it to containergrid so that it can be moved within the entire grid range.
This is similar to igoogle and other similar drag-and-drop frameworks. When you drag a drag-and-drop control, a shadowgrid is added to the original position of the drag-and-drop control to occupy space:
Public shadowgrid (dragablegrid origingrid, containerpanel parentpanel)
{
Initializecomponent ();
This. _ orgingrid = origingrid;
// Set the style of the Shadow grid to be consistent with that of the original grid.
This. width = _ orgingrid. actualwidth;
This. Height = _ orgingrid. actualheight;
This. Text = _ orgingrid. text;
This. Margin = _ orgingrid. margin;
// Set the parent Panel of the Shadow grid and insert it.
_ Vindex = parentpanel. Children. indexof (_ orgingrid );
_ Hindex = parentpanel. index;
Parentpanel. Children. insert (_ vindex + 1, this );
} Here, the shadow control and the drag-and-drop control reference each other to facilitate future operations.
Move the mouse:
Determine the isdraging position, and then set the control margin based on the new position of the mouse:
If (isdraging)
{
Point newposition = E. getposition (_ parentgrid );
This. margin = New thickness (newposition. x-_ beginpoint. x, newposition. y-_ beginpoint. y, _ parentgrid. actualwidth-this. actualwidth-newposition. X + _ beginpoint. x, _ parentgrid. actualheight-this. actualheight-newposition. Y + _ beginpoint. Y );
The displacement of the mouse relative to the control is used here, that is, the _ beginpoint is unchanged.
Next is the most troublesome part: Determine the Drag and Drop status of the control based on the new location. Here there are two situations: Moving left and right and moving up and down.
The first is relatively simple left and right movement:
// shift left
If (this. margin. left <_ parentgrid. panelwidth * (shadowgrid. hindex-0.5)
{< br> If (shadowgrid. hindex> 0)
{< br> containerpanel = This. _ parentgrid. childpanels [shadowgrid. hindex-1];
shadowgrid. moveTo (panel);
}< BR >}< br> // shift right
else if (this. margin. left> _ parentgrid. panelwidth * (shadowgrid. hindex + 0.5)
{< br> If (shadowgrid. hindex <_ parentgrid. panelcount-1)
{< br> containerpanel = This. _ parentgrid. childpanels [shadowgrid. hindex + 1];
shadowgrid. moveTo (panel);
}< BR >}_ parentgrid. panelwidth indicates the width of each column, while shadowgrid. hindex indicates the serial number of the column where shadowgrid is located. The moveTo method of shadowgrid inserts shadowgrid horizontally into another panel:
Public void moveTo (containerpanel)
{
Parentpanel. Children. Remove (this );
If (panel. Children. Count> _ vindex)
{
Panel. Children. insert (_ vindex, this );
}
Else
{
_ Vindex = panel. Children. count;
Panel. Children. Add (this );
}
This. _ hindex = panel. index;
} _ Vindex indicates the position of shadowgrid in the column.
Then it is complicated to move up and down:
// Move up
Bool hasmove = false;
If (shadowgrid. vindex> 0)
{
Control upcontrol = shadowgrid. parentpanel. Children [shadowgrid. vindex-1] as control;
Point uppoint = E. getposition (upcontrol );
If (uppoint. Y-_ beginpoint. Y) <upcontrol. actualheight/2)
{
Shadowgrid. moveTo (shadowgrid. vindex-1 );
Hasmove = true;
}
}
// Move down
If (! Hasmove & shadowgrid. vindex <shadowgrid. parentpanel. Children. Count-1)
{
Control downcontrol = shadowgrid. parentpanel. Children [shadowgrid. vindex + 1] as control;
Point downpoint = E. getposition (downcontrol );
If (_ beginpoint. Y-downpoint. Y) <this. actualheight/2)
{
Shadowgrid. moveTo (shadowgrid. vindex + 1 );
}
} Because Silverlight does not provide a method to directly obtain the relative displacement of two controls as WPF does, the size of the control may not be fixed, therefore, you cannot calculate whether to move the panel width as you move the left or right. Fortunately, we can use the mouseeventargs e of the mouse to obtain the current position of the mouse and the displacement of other controls, so as to indirectly calculate the positions of the two controls. Another overloaded moveTo method of shadowgrid implements moving shadowgrid from one position to another in one panel:
Public void moveTo (INT newvindex)
{
Containerpanel = parentpanel;
Panel. Children. Remove (this );
_ Vindex = newvindex;
Panel. Children. insert (_ vindex, this );
} Left-click lift or exit (drag and drop to end)
The logic for lift and exit is the same:
Void dragablegrid_mouseleave (Object sender, mouseeventargs E)
{
_ Parentgrid. Children. Remove (this );
Realeaseshadow ();
Isdraging = false;
} Public void realeaseshadow ()
{
If (this. shadowgrid! = NULL)
{
This. shadowgrid. Release ();
}
This. shadowgrid = NULL;
} The release method of shadowgrid removes itself from the parent container, and places the original drag-and-drop control to the position of shadowgrid.
Public void release ()
{
This. _ orgingrid. Margin = This. margin;
Containerpanel = parentpanel;
Panel. Children. Remove (this );
Panel. Children. insert (_ vindex, _ orgingrid );
} Note:
1. as moving the mouse is a very fast process, the mousemove event may trigger multiple times. If moving too fast, the operation may fail, resulting in the mouse moving away from the Drag Control, the mouse then returns the control, which may cause problems. Therefore, some seemingly redundant checks are required in some places. For example, in the realeaseshadow method, check whether the shadowgrid is empty.
2. because stackpanel and grid are used, the controls in the panel adopt the strech style by default, that is, they are filled with the entire container. For the controls in the panel, no width is specified, therefore, the actualwidth attribute of the control is used here, that is, the actual display width. This unconfigurable attribute will be obtained after the control rend.
3. if the size of the outer grid changes, you cannot set the position of the control by setting the upper and lower left margin respectively. Otherwise, the size of the control will change with the size of the grid, make sure that the width and height of the control have a fixed value, and then set the left and top alignment of the control. In this case, the margin-right and maring-bottom of the control are invalid, you only need to specify margin-top and margin-left to locate the control in the grid.
This. width = This. actualwidth;
This. Height = This. actualheight;
This. verticalalignment = verticalignment. Top;
This. horizontalalignment = horizontalalignment. Left;
// Set the initial margin.
Thickness beginmargin = New thickness (marginpoint. X-_ beginpoint. X, marginpoint. Y-_ beginpoint. Y, 0, 0 );
Source codeDownload: drag and drop the Silverlight control source code.
Ref: http://blog.csdn.net/tuoxie5431/archive/2009/03/01/3946278.aspx