Search code examples
c#wpfdrag-and-droplistboxlistboxitem

Problem with drag-and-drop WPF. Dragging button as ListBoxItem leaves blank field


I have problem while dragging items between two listboxes. While dragged item is ListBoxItem it works great, but dragging button leaves blank field.

I tried checking type of dragged item but i'm newbie in WPF and don't know how to fix it.

This is my mainWindow.xaml.cs file

private const string formatLista = "Format_Lista";
        private const string formatElement = "Format_Element";

        private void ListBox_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {

            ListBox lbSender = sender as ListBox;

            ListBoxItem element = lbSender.GetItemAt(e.GetPosition(lbSender));
            if (element == null) return;

            var item = VisualTreeHelper.HitTest(lbSender, e.GetPosition(lbSender)).VisualHit;

            DataObject dane = new DataObject();
            dane.SetData(formatLista, lbSender);
            dane.SetData(formatElement, element);            

            DragDrop.DoDragDrop(lbSender, dane, DragDropEffects.Move | DragDropEffects.Copy);
        }

        private void ListBox_DragEnter(object sender, DragEventArgs e)
        {
            if (e.KeyStates.HasFlag(DragDropKeyStates.ControlKey))
                e.Effects = DragDropEffects.Copy;
            else e.Effects = DragDropEffects.Move;
        }

        private void ListBox_Drop(object sender, DragEventArgs e)
        {
            ListBox lbSender = sender as ListBox;
            ListBox lbŹródło = e.Data.GetData(formatLista) as ListBox;
            ListBoxItem element = e.Data.GetData(formatElement) as ListBoxItem;

            if (e.KeyStates.HasFlag(DragDropKeyStates.ControlKey))
            {
                element = new ListBoxItem() { Content = element.Content };
            }
            else lbŹródło.Items.Remove(element);

            lbSender.Items.Add(element);
        }

There is GetitemAt class which I have used in above code

public static class ListBoxExtensions
    {
        public static ListBoxItem GetItemAt(this ListBox listBox, Point position)
        {
            var item = VisualTreeHelper.HitTest(listBox, position).VisualHit;
            while(item != null && !(item is ListBoxItem))
            {
                item = VisualTreeHelper.GetParent(item);
            }
            return item as ListBoxItem;
        }

    }

and here xaml code:

<Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="5" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <ListBox Grid.Column="0" 
                 PreviewMouseLeftButtonDown="ListBox_PreviewMouseLeftButtonDown"
                 AllowDrop="True" DragEnter="ListBox_DragEnter"
                 Drop="ListBox_Drop">
            <ListBoxItem Content="List 1, element 1" />
            <ListBoxItem Content="List 1, element 2" />
            <ListBoxItem Content="List 1, element 3" />
            <ListBoxItem Content="List 1, element 4" />
            <ListBoxItem Content="List 1, element 5" />
            <Button Content="List 1, button" />
        </ListBox>
        <ListBox Grid.Column="2"
                 PreviewMouseLeftButtonDown="ListBox_PreviewMouseLeftButtonDown"
                 AllowDrop="True" DragEnter="ListBox_DragEnter"
                 Drop="ListBox_Drop">
            <ListBoxItem Content="List 2, element 1" />
            <ListBoxItem Content="List 2, element 2" />
            <ListBoxItem Content="List 2, element 3" />
            <ListBoxItem Content="List 2, element 4" />
            <ListBoxItem Content="List 2, element 5" />
            <Button Content="Lista 2, button" />
        </ListBox>
</Grid>

I need dragging buttons between listbox like listboxitem


Solution

  • I think you should initially wrap each Button in a ListBoxItem like this:

        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="5" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <ListBox Grid.Column="0" 
                     PreviewMouseLeftButtonDown="ListBox_PreviewMouseLeftButtonDown"
                     AllowDrop="True" DragEnter="ListBox_DragEnter"
                     Drop="ListBox_Drop">
                <ListBoxItem Content="List 1, element 1" />
                <ListBoxItem Content="List 1, element 2" />
                <ListBoxItem Content="List 1, element 3" />
                <ListBoxItem Content="List 1, element 4" />
                <ListBoxItem Content="List 1, element 5" />
                <ListBoxItem>
                    <Button Content="List 1, button" />
                </ListBoxItem>
            </ListBox>
            <ListBox Grid.Column="2"
                     PreviewMouseLeftButtonDown="ListBox_PreviewMouseLeftButtonDown"
                     AllowDrop="True" DragEnter="ListBox_DragEnter"
                     Drop="ListBox_Drop">
                <ListBoxItem Content="List 2, element 1" />
                <ListBoxItem Content="List 2, element 2" />
                <ListBoxItem Content="List 2, element 3" />
                <ListBoxItem Content="List 2, element 4" />
                <ListBoxItem Content="List 2, element 5" />
                <ListBoxItem>
                    <Button Content="List 2, button" />
                </ListBoxItem>
            </ListBox>
        </Grid>