Core Library for WPF | ComponentOne
Core Library / DragDropManager / Walkthrough / Using DragDropManager with ListBox
In This Topic
    Using DragDropManager with ListBox
    In This Topic

    DragDropManager can be used with any UI control to enable drag-drop capability in the application. Consider a scenario where you want to implement drag and drop operation between two ListBox controls. This walkthrough explains how you can use the DragDropManager to drag and drop items between two ListBox controls in an application.

    The GIF below depicts the result:

    Dragging and dropping items using DragDropManager with ListBox

    To create this application, complete the following steps:

    Set up the application UI

    1. Create a new WPF App in Visual Studio.
    2. Switch to designer view to add two ListBox controls in the grid. For this purpose, paste the code as given below between the grid tags. So, you'll have two ListBoxes with borders. You can add textblocks at the top of each ListBox to give a heading for each ListBox, just like it is given in the GIF.
      XAML
      Copy Code
              <Border Style="{StaticResource CE_SampleBkg}" Grid.Row="2" Background="#FFF1F1F1" BorderBrush="#FFCBD2DB" BorderThickness="1,0,1,1" />
              <ListBox x:Name="_list1" Grid.Row="2" />
              <Border Style="{StaticResource CE_SampleTitleBkg}" Background="#FFECEDED" Grid.Row="1" BorderThickness="1">
                  <TextBlock Text="Physics Class" Style="{StaticResource CE_SampleTitleText}" />
              </Border>
              <Border Style="{StaticResource CE_SampleBkg}" Grid.Row="2" Background="#FFF1F1F1" Grid.Column="2" BorderBrush="#FFCBD2DB" BorderThickness="1,0,1,1" />
              <ListBox x:Name="_list2" Grid.Row="2" Grid.Column="2" />
              <Border Style="{StaticResource CE_SampleTitleBkg}" Background="#FFECEDED" Grid.Column="2" Grid.Row="1" BorderThickness="1">
                  <TextBlock Text="Mathematics Class" Style="{StaticResource CE_SampleTitleText}" />
              </Border>           
      
    3. Set styling for ListBoxes, textblocks and borders by adding the below code before the Grid tags.
      XAML
      Copy Code
       <Window.Resources>
                          <Style x:Key="ItemStyle" TargetType="Border">
                          <Setter Property="Height" Value="50" />
                          <Setter Property="Width" Value="50" />
                          <Setter Property="Margin" Value="5 5 10 5" />
                          <Setter Property="CornerRadius" Value="3" />
                          <Setter Property="BorderThickness" Value="2" />
                          <Setter Property="BorderBrush" Value="#FF8FB4CC" />
                      </Style>
                      <SolidColorBrush x:Key="CE_SampleForeground" Color="#FFF0F8FE" />
                      <Style x:Key="CE_SampleText" TargetType="TextBlock">
                          <Setter Property="VerticalAlignment" Value="Center" />
                          <Setter Property="TextWrapping" Value="Wrap" />
                          <Setter Property="Foreground" Value="#FFF0F8FE" />
                          <Setter Property="FontFamily" Value="Portable User Interface" />
                          <Setter Property="FontSize" Value="11" />
                      </Style>
                      <Style x:Key="CE_SampleTextBkg" TargetType="Border">
                          <Setter Property="Background">
                              <Setter.Value>
                                  <LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5">
                                      <GradientStop Color="#99071D2E" Offset="0.003" />
                                      <GradientStop Color="#00071D2E" Offset="1" />
                                  </LinearGradientBrush>
                              </Setter.Value>
                          </Setter>
                          <Setter Property="CornerRadius" Value="2" />
                          <Setter Property="Height" Value="26" />
                          <Setter Property="Padding" Value="10 0 0 0" />
                      </Style>
                      <Style x:Key="CE_SampleTitleBkg" TargetType="Border">
                          <Setter Property="BorderBrush" Value="#FFCBD2DB" />
                          <Setter Property="BorderThickness" Value="0,0,0,3" />
                          <Setter Property="Background">
                              <Setter.Value>
                                  <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                      <GradientStop Color="#FFE9ECF0" Offset="0" />
                                      <GradientStop Color="#FFDDE1E7" Offset="0.2" />
                                      <GradientStop Color="#FFCCD3DC" Offset="0.2" />
                                      <GradientStop Color="#FFFAFAFB" Offset="0.647" />
                                  </LinearGradientBrush>
                              </Setter.Value>
                          </Setter>
                      </Style>
                      <Style x:Key="CE_SampleTitleText" TargetType="TextBlock">
                          <Setter Property="HorizontalAlignment" Value="Left" />
                          <Setter Property="VerticalAlignment" Value="Center" />
                          <Setter Property="FontFamily" Value="Trebuchet MS" />
                          <Setter Property="FontSize" Value="16" />
                          <Setter Property="Foreground" Value="#FF507494" />
                          <Setter Property="TextWrapping" Value="NoWrap" />
                          <Setter Property="Margin" Value="10 5" />
                      </Style>
                      <Style x:Key="CE_SampleBkg" TargetType="Border">
                          <Setter Property="Background" Value="#99071D2E" />
                          <Setter Property="BorderBrush" Value="#FF071D2E" />
                          <Setter Property="BorderThickness" Value="1" />
                      </Style>
              <DataTemplate x:Key="StudentTemplate">
                  <Grid Background="Transparent">
                      <Grid.ColumnDefinitions>
                          <ColumnDefinition Width="Auto" />
                          <ColumnDefinition Width="*" />
                      </Grid.ColumnDefinitions>
                      <Border HorizontalAlignment="Left" VerticalAlignment="Center" Style="{StaticResource ItemStyle}">
                          <Grid>
                              <Rectangle Stroke="#FF7E7E7E" RadiusY="1" Fill="White" RadiusX="1" />
                              <Rectangle Stroke="#FFABB1B3" RadiusY="1" Margin="3,3,3,9">
                                  <Rectangle.Fill>
                                      <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                          <GradientStop Color="#FFD7D7D7" />
                                          <GradientStop Color="#FFFFFFFF" Offset="0.652" />
                                      </LinearGradientBrush>
                                  </Rectangle.Fill>
                              </Rectangle>
                              <Path Stretch="Fill" Stroke="{x:Null}" Margin="4,6,4,10" Data="M17.60116,6.1738421E-05 C24.849646,0.023804173 26.683809,6.5920992 26.299255,12.14412 C25.308187,19.035593 23.641359,20.055075 22.426523,20.763863 C22.011572,22.301838 22.281172,23.129519 22.872089,23.413864 C25.789896,24.566036 28.26816,25.747917 31.26363,26.867565 C33.701267,28.11087 34.777184,28.794552 35.861771,29.767353 L38.065468,34.026146 C38.065468,34.026146 -2.0894244,33.953915 -2.0894244,33.953915 L0,29.600348 L0.0063374043,29.592121 C0.76684761,28.636683 2.0420403,27.542118 4.10077,26.985603 C8.0647907,25.539055 10.515559,24.379763 11.685194,23.874727 C12.629223,23.317556 13.257205,21.523518 12.521232,20.930931 C10.421399,19.15081 8.8502626,17.703053 8.3638849,11.022204 C7.883646,6.7073164 10.405101,-0.023508755 17.60116,6.1738421E-05 z">
                                  <Path.Fill>
                                      <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                          <GradientStop Color="#FF516D7C" Offset="0.012" />
                                          <GradientStop Color="#33516D7C" Offset="1" />
                                      </LinearGradientBrush>
                                  </Path.Fill>
                              </Path>
                              <Path Fill="#3FFFFFFF" Stretch="Fill" Data="M0,0 L21.185122,0 C21.588734,0.12784213 21.858183,0.39503863 22,0.79480571 L22,24 C18.573542,13.458178 11.15755,5.5119557 0,0 z" HorizontalAlignment="Left" VerticalAlignment="Top" />
                          </Grid>
                      </Border>
                      <StackPanel Orientation="Horizontal" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center">
                          <TextBlock Text="{Binding Name}" TextWrapping="Wrap" FontFamily="Arial" FontSize="12" VerticalAlignment="Top" Foreground="#FF222222" />
                          <TextBlock Text="{Binding Surname}" TextWrapping="Wrap" FontFamily="Arial" FontSize="12" VerticalAlignment="Top" Foreground="#FF222222" />
                      </StackPanel>
                  </Grid>
              </DataTemplate>
              <Style TargetType="ListBox">
                          <Setter Property="Background" Value="Transparent" />
                          <Setter Property="BorderBrush" Value="{x:Null}" />
                          <Setter Property="Margin" Value="0,1,1,1" />
                          <Setter Property="ItemContainerStyle">
                              <Setter.Value>
                                  <Style TargetType="ListBoxItem">
                                      <Setter Property="HorizontalContentAlignment" Value="Stretch" />
                                  </Style>
                              </Setter.Value>
                          </Setter>
                      </Style>
                         </Window.Resources>
      

    Create data source for ListBox

    Here we are using class, as a datasource, with the ListBox. Hence create a class by the name Person to populate ListBox with data.

    C#
    Copy Code
     class Person
        {
            public string Name { get; set; }
            private static Random Randomizer = new Random();
            public static List<Person> Generate(int qty)
            {
                var items = new List<Person>();
                for (int i = 0; i < qty; i++)
                {
                    items.Add(new Person()
                    {
                        Name = Names[Randomizer.Next(Names.Length)] + " " + Surnames[Randomizer.Next(Surnames.Length)],                                
                    });
                }
                return items;
            }
            private static string[] Names = new string[]
            {
                "Michael",
                "John",
                "Bernardo",
                "Alvaro",
                "Max",
                "Leonard",
                "Noela",
                "Gabriel",
                "Bruno",
                "Rodrigo",
                "Sheela",
                "Chris",
                "Martin",
                "Ben",
                "Alex",
                "Irina",
                "Dave",
                "Patric",
            };
           private static string[] Surnames = new string[]
            {
                "Johnson",
                "Alvarez",
                "Maxtor",
                "Johansen",
                "Vera",
                "García",
                "Days",
                "Castle",
                "Varela",
                "Smith",
                "Gates",
                "Meredith",
                "Drexler",
                "Beckham",
                "Jobs",
            };     
        }
    

    Configure drag-drop functionality in Listbox

    1. In the Code Editor, declare and initialize an object of C1DragDropManager class.
      C#
      Copy Code
      // create and initialize DragDropManager class
       C1DragDropManager _dd;
      _dd = new C1DragDropManager();  
      
    2. Register the two ListBoxes as drop target and drag source. Also set a Drag Threshold value to prevent the accidental or unwanted drag action.
      C#
      Copy Code
      // register drop targets
                  foreach (ListBox lb in new ListBox[] { _list1, _list2 })
                  {
                      _dd.RegisterDropTarget(lb, true);
                      foreach (Person p in Person.Generate(5))
                      {
                          var personElement = new ContentPresenter();
                          personElement.Content = p;
                          personElement.ContentTemplate = (DataTemplate)Resources["StudentTemplate"];
                          lb.Items.Add(personElement);
                          _dd.RegisterDragSource(personElement, DragDropEffect.Move, ModifierKeys.None);
                          // Set a distance for the mouse to move before a drag operation starts
                          _dd.DragThreshold = 5;
                          personElement.MouseDown += (s, e) =>
                          {
                              // _dd is the first to get the event.
                              // Then we mark it handled to inhibit ListBox selection stealing _dd's mouse capture.
                              e.Handled = true;
                          };
                      }
                  }
      
    3. Subscribe to the DragDrop event.
      C#
      Copy Code
       // handle the drops
       _dd.DragDrop += _dd_DragDrop;
      
    4. Handle the drops with the DragDrop event. Here, we get the drop location within a ListBox using GetDropIndex method. This method passes the DragDropEventArgs object and ListBox as parameters.
      C#
      Copy Code
              void _dd_DragDrop(object source, DragDropEventArgs e)
              {
                  // get object being dragged
                  UIElement sourceElement = e.DragSource;
                  // get source parent, target listboxes
                  ListBox sourceParent = _list1.Items.Contains(sourceElement) ? _list1 : _list2;
                  ListBox target = e.DropTarget as ListBox;
                 // get index into target
                  int index = GetDropIndex(e, target);
                  // adjust index
                  if (sourceParent == target)
                  {
                      int sourceIndex = sourceParent.Items.IndexOf(sourceElement);
                      if (index > sourceParent.Items.IndexOf(sourceElement))
                      {
                          index--;
                      }
                      if (index == sourceIndex)
                          return;
                  }
                  // remove from original position, insert into new position
                  sourceParent.Items.Remove(sourceElement);
                  target.Items.Insert(index, sourceElement);
              }
              #region ** utility
              // get drop location within a ListBox
              public static int GetDropIndex(DragDropEventArgs e, ListBox target)
              {
                  int index = 0;
                  foreach (UIElement child in target.Items)
                  {
                      Point p = e.GetPosition(child);
                      if (p.Y - child.DesiredSize.Height / 2 < 0) break;
                      index++;
                  }
                  return index;
              }
          }
      
    5. Now, execute the application and observe the output.

    Drag an item from one ListBox and drop to the other ListBox, and vice-versa hence it concludes the walkthrough for implementing drag-drop feature with ListBoxes in applications.