我想在主窗口中放置一个wpf窗口。
我尝试制作一个对象,然后像这样将窗口内容传递给它
childWindow child = new childWindow();
object obj = child.content;
child.content = null;
child.Close();
myGrid.Children.Add((UIElement)obj);
但是我希望它在主窗口内移动(例如拖动和移动)。
提前谢谢。
答案 0 :(得分:1)
我不记得我从哪里买来的,但是效果很好。它就像另一个容器内的窗口一样。
使用XAML优先
<util:DragCanvas Panel.ZIndex="1" Visibility="{Binding ShowCustomerApprovals, Converter={StaticResource BooleanToVisibilityConverter1}, FallbackValue=Hidden}"></unil:DragCanvas>
班级
public class DragCanvas : Canvas
{
#region Data
// Stores a reference to the UIElement currently being dragged by the user.
private UIElement elementBeingDragged;
// Keeps track of where the mouse cursor was when a drag operation began.
private Point origCursorLocation;
// The offsets from the DragCanvas' edges when the drag operation began.
private double origHorizOffset, origVertOffset;
// Keeps track of which horizontal and vertical offset should be modified for the drag element.
private bool modifyLeftOffset, modifyTopOffset;
// True if a drag operation is underway, else false.
private bool isDragInProgress;
#endregion // Data
#region Attached Properties
#region CanBeDragged
public static readonly DependencyProperty CanBeDraggedProperty;
public static bool GetCanBeDragged(UIElement uiElement)
{
if (uiElement == null)
return false;
return (bool)uiElement.GetValue(CanBeDraggedProperty);
}
public static void SetCanBeDragged(UIElement uiElement, bool value)
{
if (uiElement != null)
uiElement.SetValue(CanBeDraggedProperty, value);
}
#endregion // CanBeDragged
#endregion // Attached Properties
#region Dependency Properties
public static readonly DependencyProperty AllowDraggingProperty;
public static readonly DependencyProperty AllowDragOutOfViewProperty;
#endregion // Dependency Properties
#region Static Constructor
static DragCanvas()
{
AllowDraggingProperty = DependencyProperty.Register(
"AllowDragging",
typeof(bool),
typeof(DragCanvas),
new PropertyMetadata(true));
AllowDragOutOfViewProperty = DependencyProperty.Register(
"AllowDragOutOfView",
typeof(bool),
typeof(DragCanvas),
new UIPropertyMetadata(false));
CanBeDraggedProperty = DependencyProperty.RegisterAttached(
"CanBeDragged",
typeof(bool),
typeof(DragCanvas),
new UIPropertyMetadata(true));
}
#endregion // Static Constructor
#region Constructor
/// <summary>
/// Initializes a new instance of DragCanvas. UIElements in
/// the DragCanvas will immediately be draggable by the user.
/// </summary>
public DragCanvas()
{
}
#endregion // Constructor
#region Interface
#region AllowDragging
/// <summary>
/// Gets/sets whether elements in the DragCanvas should be draggable by the user.
/// The default value is true. This is a dependency property.
/// </summary>
public bool AllowDragging
{
get { return (bool)base.GetValue(AllowDraggingProperty); }
set { base.SetValue(AllowDraggingProperty, value); }
}
#endregion // AllowDragging
#region AllowDragOutOfView
/// <summary>
/// Gets/sets whether the user should be able to drag elements in the DragCanvas out of
/// the viewable area. The default value is false. This is a dependency property.
/// </summary>
public bool AllowDragOutOfView
{
get { return (bool)GetValue(AllowDragOutOfViewProperty); }
set { SetValue(AllowDragOutOfViewProperty, value); }
}
#endregion // AllowDragOutOfView
#region BringToFront / SendToBack
/// <summary>
/// Assigns the element a z-index which will ensure that
/// it is in front of every other element in the Canvas.
/// The z-index of every element whose z-index is between
/// the element's old and new z-index will have its z-index
/// decremented by one.
/// </summary>
/// <param name="targetElement">
/// The element to be sent to the front of the z-order.
/// </param>
public void BringToFront(UIElement element)
{
this.UpdateZOrder(element, true);
}
/// <summary>
/// Assigns the element a z-index which will ensure that
/// it is behind every other element in the Canvas.
/// The z-index of every element whose z-index is between
/// the element's old and new z-index will have its z-index
/// incremented by one.
/// </summary>
/// <param name="targetElement">
/// The element to be sent to the back of the z-order.
/// </param>
public void SendToBack(UIElement element)
{
this.UpdateZOrder(element, false);
}
#endregion // BringToFront / SendToBack
#region ElementBeingDragged
/// <summary>
/// Returns the UIElement currently being dragged, or null.
/// </summary>
/// <remarks>
/// Note to inheritors: This property exposes a protected
/// setter which should be used to modify the drag element.
/// </remarks>
public UIElement ElementBeingDragged
{
get
{
if (!this.AllowDragging)
return null;
else
return this.elementBeingDragged;
}
protected set
{
if (this.elementBeingDragged != null)
this.elementBeingDragged.ReleaseMouseCapture();
if (!this.AllowDragging)
this.elementBeingDragged = null;
else
{
if (DragCanvas.GetCanBeDragged(value))
{
this.elementBeingDragged = value;
this.elementBeingDragged.CaptureMouse();
}
else
this.elementBeingDragged = null;
}
}
}
#endregion // ElementBeingDragged
#region FindCanvasChild
/// <summary>
/// Walks up the visual tree starting with the specified DependencyObject,
/// looking for a UIElement which is a child of the Canvas. If a suitable
/// element is not found, null is returned. If the 'depObj' object is a
/// UIElement in the Canvas's Children collection, it will be returned.
/// </summary>
/// <param name="depObj">
/// A DependencyObject from which the search begins.
/// </param>
public UIElement FindCanvasChild(DependencyObject depObj)
{
while (depObj != null)
{
// If the current object is a UIElement which is a child of the
// Canvas, exit the loop and return it.
UIElement elem = depObj as UIElement;
if (elem != null && base.Children.Contains(elem))
break;
// VisualTreeHelper works with objects of type Visual or Visual3D.
// If the current object is not derived from Visual or Visual3D,
// then use the LogicalTreeHelper to find the parent element.
if (depObj is Visual || depObj is Visual3D)
depObj = VisualTreeHelper.GetParent(depObj);
else
depObj = LogicalTreeHelper.GetParent(depObj);
}
return depObj as UIElement;
}
#endregion // FindCanvasChild
#endregion // Interface
#region Overrides
#region OnPreviewMouseLeftButtonDown
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
this.isDragInProgress = false;
// Cache the mouse cursor location.
this.origCursorLocation = e.GetPosition(this);
// Walk up the visual tree from the element that was clicked,
// looking for an element that is a direct child of the Canvas.
this.ElementBeingDragged = this.FindCanvasChild(e.Source as DependencyObject);
if (this.ElementBeingDragged == null)
return;
// Get the element's offsets from the four sides of the Canvas.
double left = Canvas.GetLeft(this.ElementBeingDragged);
double right = Canvas.GetRight(this.ElementBeingDragged);
double top = Canvas.GetTop(this.ElementBeingDragged);
double bottom = Canvas.GetBottom(this.ElementBeingDragged);
// Calculate the offset deltas and determine for which sides
// of the Canvas to adjust the offsets.
this.origHorizOffset = ResolveOffset(left, right, out this.modifyLeftOffset);
this.origVertOffset = ResolveOffset(top, bottom, out this.modifyTopOffset);
// Set the Handled flag so that a control being dragged
// does not react to the mouse input.
e.Handled = true;
this.isDragInProgress = true;
}
#endregion // OnPreviewMouseLeftButtonDown
#region OnPreviewMouseMove
protected override void OnPreviewMouseMove(MouseEventArgs e)
{
base.OnPreviewMouseMove(e);
// If no element is being dragged, there is nothing to do.
if (this.ElementBeingDragged == null || !this.isDragInProgress)
return;
// Get the position of the mouse cursor, relative to the Canvas.
Point cursorLocation = e.GetPosition(this);
// These values will store the new offsets of the drag element.
double newHorizontalOffset, newVerticalOffset;
#region Calculate Offsets
// Determine the horizontal offset.
if (this.modifyLeftOffset)
newHorizontalOffset = this.origHorizOffset + (cursorLocation.X - this.origCursorLocation.X);
else
newHorizontalOffset = this.origHorizOffset - (cursorLocation.X - this.origCursorLocation.X);
// Determine the vertical offset.
if (this.modifyTopOffset)
newVerticalOffset = this.origVertOffset + (cursorLocation.Y - this.origCursorLocation.Y);
else
newVerticalOffset = this.origVertOffset - (cursorLocation.Y - this.origCursorLocation.Y);
#endregion // Calculate Offsets
if (!this.AllowDragOutOfView)
{
#region Verify Drag Element Location
// Get the bounding rect of the drag element.
Rect elemRect = this.CalculateDragElementRect(newHorizontalOffset, newVerticalOffset);
//
// If the element is being dragged out of the viewable area,
// determine the ideal rect location, so that the element is
// within the edge(s) of the canvas.
//
bool leftAlign = elemRect.Left < 0;
bool rightAlign = elemRect.Right > this.ActualWidth;
if (leftAlign)
newHorizontalOffset = modifyLeftOffset ? 0 : this.ActualWidth - elemRect.Width;
else if (rightAlign)
newHorizontalOffset = modifyLeftOffset ? this.ActualWidth - elemRect.Width : 0;
bool topAlign = elemRect.Top < 0;
bool bottomAlign = elemRect.Bottom > this.ActualHeight;
if (topAlign)
newVerticalOffset = modifyTopOffset ? 0 : this.ActualHeight - elemRect.Height;
else if (bottomAlign)
newVerticalOffset = modifyTopOffset ? this.ActualHeight - elemRect.Height : 0;
#endregion // Verify Drag Element Location
}
#region Move Drag Element
if (this.modifyLeftOffset)
Canvas.SetLeft(this.ElementBeingDragged, newHorizontalOffset);
else
Canvas.SetRight(this.ElementBeingDragged, newHorizontalOffset);
if (this.modifyTopOffset)
Canvas.SetTop(this.ElementBeingDragged, newVerticalOffset);
else
Canvas.SetBottom(this.ElementBeingDragged, newVerticalOffset);
#endregion // Move Drag Element
}
#endregion // OnPreviewMouseMove
#region OnHostPreviewMouseUp
protected override void OnPreviewMouseUp(MouseButtonEventArgs e)
{
base.OnPreviewMouseUp(e);
// Reset the field whether the left or right mouse button was
// released, in case a context menu was opened on the drag element.
this.ElementBeingDragged = null;
}
#endregion // OnHostPreviewMouseUp
#endregion // Host Event Handlers
#region Private Helpers
#region CalculateDragElementRect
/// <summary>
/// Returns a Rect which describes the bounds of the element being dragged.
/// </summary>
private Rect CalculateDragElementRect(double newHorizOffset, double newVertOffset)
{
if (this.ElementBeingDragged == null)
throw new InvalidOperationException("ElementBeingDragged is null.");
Size elemSize = this.ElementBeingDragged.RenderSize;
double x, y;
if (this.modifyLeftOffset)
x = newHorizOffset;
else
x = this.ActualWidth - newHorizOffset - elemSize.Width;
if (this.modifyTopOffset)
y = newVertOffset;
else
y = this.ActualHeight - newVertOffset - elemSize.Height;
Point elemLoc = new Point(x, y);
return new Rect(elemLoc, elemSize);
}
#endregion // CalculateDragElementRect
#region ResolveOffset
/// <summary>
/// Determines one component of a UIElement's location
/// within a Canvas (either the horizontal or vertical offset).
/// </summary>
/// <param name="side1">
/// The value of an offset relative to a default side of the
/// Canvas (i.e. top or left).
/// </param>
/// <param name="side2">
/// The value of the offset relative to the other side of the
/// Canvas (i.e. bottom or right).
/// </param>
/// <param name="useSide1">
/// Will be set to true if the returned value should be used
/// for the offset from the side represented by the 'side1'
/// parameter. Otherwise, it will be set to false.
/// </param>
private static double ResolveOffset(double side1, double side2, out bool useSide1)
{
// If the Canvas.Left and Canvas.Right attached properties
// are specified for an element, the 'Left' value is honored.
// The 'Top' value is honored if both Canvas.Top and
// Canvas.Bottom are set on the same element. If one
// of those attached properties is not set on an element,
// the default value is Double.NaN.
useSide1 = true;
double result;
if (Double.IsNaN(side1))
{
if (Double.IsNaN(side2))
{
// Both sides have no value, so set the
// first side to a value of zero.
result = 0;
}
else
{
result = side2;
useSide1 = false;
}
}
else
{
result = side1;
}
return result;
}
#endregion // ResolveOffset
#region UpdateZOrder
/// <summary>
/// Helper method used by the BringToFront and SendToBack methods.
/// </summary>
/// <param name="element">
/// The element to bring to the front or send to the back.
/// </param>
/// <param name="bringToFront">
/// Pass true if calling from BringToFront, else false.
/// </param>
private void UpdateZOrder(UIElement element, bool bringToFront)
{
#region Safety Check
if (element == null)
throw new ArgumentNullException("element");
if (!base.Children.Contains(element))
throw new ArgumentException("Must be a child element of the Canvas.", "element");
#endregion // Safety Check
#region Calculate Z-Indici And Offset
// Determine the Z-Index for the target UIElement.
int elementNewZIndex = -1;
if (bringToFront)
{
foreach (UIElement elem in base.Children)
if (elem.Visibility != Visibility.Collapsed)
++elementNewZIndex;
}
else
{
elementNewZIndex = 0;
}
// Determine if the other UIElements' Z-Index
// should be raised or lowered by one.
int offset = (elementNewZIndex == 0) ? +1 : -1;
int elementCurrentZIndex = Canvas.GetZIndex(element);
#endregion // Calculate Z-Indici And Offset
#region Update Z-Indici
// Update the Z-Index of every UIElement in the Canvas.
foreach (UIElement childElement in base.Children)
{
if (childElement == element)
Canvas.SetZIndex(element, elementNewZIndex);
else
{
int zIndex = Canvas.GetZIndex(childElement);
// Only modify the z-index of an element if it is
// in between the target element's old and new z-index.
if (bringToFront && elementCurrentZIndex < zIndex ||
!bringToFront && zIndex < elementCurrentZIndex)
{
Canvas.SetZIndex(childElement, zIndex + offset);
}
}
}
#endregion // Update Z-Indici
}
#endregion // UpdateZOrder
#endregion // Private Helpers
}