Automatic sizing and stretch of DragSource and DropTarget contents

Feb 10, 2010 at 9:40 AM

Hi

Awesome drag drop control, it seems to have all the bells and whistles I need, apart from one. I'm not sure if it's because I'm a silverlight n00b or if there's a problem with the control, but here goes.

If I have the following markup, I get a nice big textbox in the second column of the grid

 

<UserControl x:Class="SL_Drag_Drop.sucDanFudge"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:dragdrop="clr-namespace:SL_Drag_Drop_BaseClasses;assembly=SL_Drag_Drop_BaseClasses"
    >
    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"></ColumnDefinition>
            <ColumnDefinition Width="*"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        
        <ListBox Grid.Column="0"><!-- pretend there's some list content here --></ListBox>

        <TextBox Grid.Column="1" Text="yar" Width="Auto" Height="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"></TextBox>
    </Grid>
</UserControl>

If I however wrap said textbox in a DropTarget, it shrinks the textbox down and centers it smack bang in the middle of the column

 

<UserControl x:Class="SL_Drag_Drop.sucDanFudge"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:dragdrop="clr-namespace:SL_Drag_Drop_BaseClasses;assembly=SL_Drag_Drop_BaseClasses"
    >
    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"></ColumnDefinition>
            <ColumnDefinition Width="*"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        
        <ListBox Grid.Column="0"><!-- pretend there's some list content here --></ListBox>
<dragdrop:DropTarget HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Width="Auto" Height="Auto" Grid.Column="1" > <dragdrop:DropTarget.Content> <dragdrop:DragSource DraggingEnabled="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Width="Auto" Height="Auto"> <TextBox Text="yar" Width="Auto" Height="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"></TextBox> </dragdrop:DragSource> </dragdrop:DropTarget.Content> </dragdrop:DropTarget> </Grid> </UserControl>

Does anybody have any pointers as to what could possibly be causing the textbox to lose its stretch fill? I've used SilverlightSpy to poke around in the visual tree, but nothing jumps out at me (plus I'm not entirely sure what I'm looking at... being a newbie and all). I tried banging a bunch of Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" into the generic.xml, that didn't work. I even put some extra HorizontalAlignment="{TemplateBinding HorizontalAlignment}" and VerticalAlignment="{TemplateBinding VerticalAlignment}" in some spots in generic.xml, but no joy for me.

 

Cheers!

Dan

 

 

 

 

Feb 10, 2010 at 9:43 AM

Ugh, the text composer mangled my second example. Let's try that again

 

<UserControl x:Class="SL_Drag_Drop.sucDanFudge"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:dragdrop="clr-namespace:SL_Drag_Drop_BaseClasses;assembly=SL_Drag_Drop_BaseClasses"
    >
    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"></ColumnDefinition>
            <ColumnDefinition Width="*"></ColumnDefinition>
        </Grid.ColumnDefinitions>

        <ListBox Grid.Column="0">
            <!-- pretend there's some list content here -->
        </ListBox>

        <dragdrop:DropTarget HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                                 Width="Auto" Height="Auto"
                             Grid.Column="1" 
                                 >
            <dragdrop:DropTarget.Content>
                <dragdrop:DragSource DraggingEnabled="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Width="Auto" Height="Auto">
                    <TextBox Text="yar" Width="Auto" Height="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"></TextBox>
                </dragdrop:DragSource>
            </dragdrop:DropTarget.Content>
        </dragdrop:DropTarget>
    </Grid>
</UserControl>

 

 

Feb 12, 2010 at 11:51 PM

This should work. What I've done is create an event handler for the DropTarget resizing that changes your textboxs size:

(I named your TextBox 'txtbx' and named your DropTarget dt)

dt.SizeChanged += new SizeChangedEventHandler(scrollViewerTab_SizeChanged);


        void scrollViewerTab_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            txtbx.Height = e.NewSize.Height;
            txtbx.Width = e.NewSize.Width;
        }

 

Feb 13, 2010 at 6:44 AM

Thanks J, that pointed me in the right direction. I had to modify it slightly as trying to talk directly to the textbox was throwing a NRE for me, the code that worked for me was:

 

        private void DropTarget_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            var feSender = (FrameworkElement)sender;
            var theContents = (TextBox)feSender.FindName("txtbx");
            if (theContents != null)
            {
                theContents.Height = e.NewSize.Height;
                theContents.Width = e.NewSize.Width;
            }
        }

Cheers!

Dan

 

May 20, 2010 at 5:37 PM

Hello,

I had similar sizing issues. My droptargets were set static to various sizes, all dragsouce and droptarget content and ghost controls, and the child content controls size were set to auto. 

I wanted the dragsource size to auto size to it's new target and the swaped out target to size to the original source target size. I know confusing. Below is a modification that is working great for me and not sure if this is something others can use.

I modified the DropTargetBase_InternalDragSourceDropped event in DropTarget.cs. Changes are in red.

        /// <summary>
        /// Handles the dropping of a dragsource in this droptarget
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        void DropTargetBase_InternalDragSourceDropped(object sender, DropEventArgs args)
        {
            if (ShowHover)
            {
                // after this, start the hover-out animation on the droptarget
                Animation.CreateDropTargetHoverOut(BoundingBorder).Begin();
            }

            // what if there are children?
            if (MainContentControl.Children.Count > 0)
            {
                // get the current child (which is a dragsource by definition)
                // and either switch it with the new child (if the parent of the new child
                // is a valid droptarget for the current child - so it must have rights to
                // be used as a droptarget to be able to make the switch!) or replace it DragSource currentChild = (DragSource)MainContentControl.Children[0]; // if currentchild <> child you're dragging (else, we're just dropping our
                // dragsource onto its own parent (droptarget)
                if (currentChild != args.DragSource)
                {
                    // is the new childs' parent (parent of parent of parent) a droptarget?
                    Panel firstParent = (Panel)VisualTreeHelper.GetParent(VisualTreeHelper.GetParent(args.DragSource));

                    if (firstParent != null)
                    {
                        // droptarget?
                        if (VisualTreeHelper.GetParent(firstParent) is DropTarget)
                        {
                            DropTarget newChildParentDropTarget = (DropTarget)VisualTreeHelper.GetParent(firstParent);
                            if (currentChild.DropTargets.Contains(newChildParentDropTarget)
                                || currentChild.AllDropTargetsValid == true) // check for valid droptarget, or check if all droptargets are valid
                            {

                                // point needed for animation of the current child
                                Point from = new Point();
                                from = args.DragSource.getCurrentPosition();

                                Point offsetCurrentChild = new Point();
                                if (currentChild.ShowSwitchReplaceAnimation)
                                {
                                    offsetCurrentChild = currentChild.MainDraggableControl.TransformToVisual(InitialValues.ContainingLayoutPanel).Transform(new Point(0, 0));
                                }

                                Point oriOffset = new Point(args.DragSource.OriginalOffset.X, args.DragSource.OriginalOffset.Y);


                                // reset position of dragsource, so control is on top of ghost, right
                                // before actually moving it.
                                args.DragSource.ResetMyPosition();

                                // remove from current parent
                                ((Panel)VisualTreeHelper.GetParent(args.DragSource)).Children.Remove(args.DragSource);

                                MainContentControl.Children.Clear();
                                // resize to its new parents width
                                args.DragSource.MainContentPresenter.Width = MainContentControl.ActualWidth - 2;
                                args.DragSource.MainControlHost.Width = MainContentControl.ActualWidth;
                                args.DragSource.MainDraggableControl.Width = MainContentControl.ActualWidth;
                                MainContentControl.Children.Add(args.DragSource);

                              

                                // move the current child, with or without an animation
                                if (currentChild.ShowSwitchReplaceAnimation)
                                {
                                    // animation, from the current position to the new position
                                    // current position = where the new child is now
                                    // new position = where the new child was

                                    // add the current child to its new position and resize to its new parents width,
                                    // then move it from the "current position" to 0, 0 (the new position)
                                    currentChild.MainContentPresenter.Width = newChildParentDropTarget.MainControlHost.ActualWidth - 2;
                                    currentChild.MainControlHost.Width = newChildParentDropTarget.MainControlHost.ActualWidth;
                                    currentChild.MainDraggableControl.Width = newChildParentDropTarget.MainControlHost.ActualWidth;
                                    newChildParentDropTarget.MainContentControl.Children.Add(currentChild);
                                   
                                    //currentChild.AnimateOnSwitch(from);

                                    Storyboard sb = currentChild.ReturnAnimateOnSwitch(offsetCurrentChild, oriOffset);
                               
                                    EventHandler handler = null;
                                    handler = (send, arg) =>
                                    {
                                        sb.Completed -= handler;
                                        currentChild.ResetMyPosition();
                                        //args.DragSource.Width = newChildParentDropTarget.Width;
                                        // trigger external dragsourcedropped-event
                                        TriggerDragSourceDropped(args.DragSource);
                                    };
                                    sb.Completed += handler;
                                    sb.Begin();

                                }
                                else
                                {
                                    // no animation
                                    newChildParentDropTarget.MainContentControl.Children.Add(currentChild);

                                    // trigger external dragsourcedropped-event
                                    TriggerDragSourceDropped(args.DragSource);
                                }

                            }
                            else
                            {
                                // parent of the new child isn't a VALID droptarget.  Depending on DropBehaviour, remove
                                // current child & set new one (replace-behaviour) or return the new child to
                                // its original position (disallow-behaviour)

                                if (RemoveElementDropBehaviour == RemoveElementDropBehaviour.Replace)
                                {
                                    // reset position of dragsource, so control is on top of ghost, right
                                    // before actually moving it.
                                    args.DragSource.ResetMyPosition();

                                    // remove from current parent
                                    ((Panel)VisualTreeHelper.GetParent(args.DragSource)).Children.Remove(args.DragSource);

                                    MainContentControl.Children.Clear();
                                    MainContentControl.Children.Add(args.DragSource);

                                    // trigger external dragsourcedropped-event
                                    TriggerDragSourceDropped(args.DragSource);
                                }
                                else
                                {
                                    // drop is disallowed, return dragsource to original position

                                    args.DragSource.ReturnToOriginalPosition();

                                    // trigger external dragsourcedropped-event
                                    TriggerDragSourceDropped(args.DragSource);
                                }
                            }
                        }
                        else
                        {
                            // parent of the new child isn't a droptarget.  Depending on DropBehaviour, remove
                            // current child & set new one (replace-behaviour) or return the new child to
                            // its original position (disallow-behaviour)

                            if (RemoveElementDropBehaviour == RemoveElementDropBehaviour.Replace)
                            {
                                // reset position of dragsource, so control is on top of ghost, right
                                // before actually moving it.
                                args.DragSource.ResetMyPosition();

                                // remove from current parent
                                ((Panel)VisualTreeHelper.GetParent(args.DragSource)).Children.Remove(args.DragSource);

                                MainContentControl.Children.Clear();
                                MainContentControl.Children.Add(args.DragSource);

                                // trigger external dragsourcedropped-event
                                TriggerDragSourceDropped(args.DragSource);
                            }
                            else
                            {
                                // drop is disallowed, return dragsource to original position

                                args.DragSource.ReturnToOriginalPosition();

                                // trigger external dragsourcedropped-event
                                TriggerDragSourceDropped(args.DragSource);
                            }
                        }
                    }
                    else
                    {
                        // reset position of dragsource, so control is on top of ghost, right
                        // before actually moving it.
                        args.DragSource.ResetMyPosition();

                        // remove from current parent
                        ((Panel)VisualTreeHelper.GetParent(args.DragSource)).Children.Remove(args.DragSource);

                        MainContentControl.Children.Clear();
                        MainContentControl.Children.Add(args.DragSource);

                        // trigger external dragsourcedropped-event
                        TriggerDragSourceDropped(args.DragSource);

                    }
                }
                else
                {
                    // reset position of dragsource, so control is on top of ghost, right
                    // before actually moving it.
                    args.DragSource.ResetMyPosition();

                    // trigger external dragsourcedropped-event
                    TriggerDragSourceDropped(args.DragSource);
                }

            }
            else
            {
                // reset position of dragsource, so control is on top of ghost, right
                // before actually moving it.
                args.DragSource.ResetMyPosition();

                // remove from current parent
                ((Panel)VisualTreeHelper.GetParent(args.DragSource)).Children.Remove(args.DragSource);

                MainContentControl.Children.Clear();
                MainContentControl.Children.Add(args.DragSource);

                ((DropTarget)VisualTreeHelper.GetParent((Panel)VisualTreeHelper.GetParent(VisualTreeHelper.GetParent(args.DragSource)))).Content = null;
                this.Content = args.DragSource;

                // trigger external dragsourcedropped-event
                TriggerDragSourceDropped(args.DragSource);

            }

        }