问题
I am creating a customcontrol dynamically inside a wrappanel. Now i need the reorder the custom controls which are inside the wrappanel. Is it possible to rearrange the custom controls inside the wrappanel using drag and drop?
Here is my XAML code
<DockPanel Grid.Column="1" Margin="208,40,1,94" Grid.Row="2"
Background="White" AllowDrop="True">
<ScrollViewer AllowDrop="True" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Hidden" Width="443">
<StackPanel Width="443" >
<WrapPanel x:Name="pnl" HorizontalAlignment="Left"
Height="Auto"
VerticalAlignment="Top" Width="480" AllowDrop="True"
/>
</StackPanel>
</ScrollViewer>
</DockPanel>
I've tried put the wrap panel inside the list, as it was suggested by the given answer(Ilan's answer), and now my panel is not accessible in the code behind. AM i doing anything wrong?
回答1:
Here I have demonstrated Buttons
, you can modify it for your needs.
Xaml
<WrapPanel x:Name="Pnl" Background="Yellow" Margin="0,0,0,128" Button.DragEnter="Button_DragEnter" Button.MouseRightButtonDown="Button_MouseDown">
<Button Content="Btn1" AllowDrop="True"/>
<Button Content="Btn2" AllowDrop="True"/>
<Button Content="Btn3" AllowDrop="True"/>
</WrapPanel>
Code
Button btn_to_drag;
private void Button_MouseDown(object sender, MouseButtonEventArgs e)
{
btn_to_drag = (Button)e.Source;
DragDrop.DoDragDrop(btn_to_drag, btn_to_drag, DragDropEffects.Move);
}
private void Button_DragEnter(object sender, DragEventArgs e)
{
Button btn = (Button)e.Source;
int where_to_drop = Pnl.Children.IndexOf(btn);
Pnl.Children.Remove(btn_to_drag);
Pnl.Children.Insert(where_to_drop, btn_to_drag);
}
Another approach using DataObject
removing the need for btn_to_drag
declaration.
private void Button_MouseDown(object sender, MouseButtonEventArgs e)
{
DataObject data = new DataObject(DataFormats.Serializable, (Button)e.Source );
DragDrop.DoDragDrop((DependencyObject)e.Source, data, DragDropEffects.Move);
}
private void Button_DragEnter(object sender, DragEventArgs e)
{
Button btn_to_move = (Button) e.Data.GetData(DataFormats.Serializable);
int where_to_move = Pnl.Children.IndexOf((UIElement)e.Source);
int what_to_move = Pnl.Children.IndexOf(btn_to_move);
Pnl.Children.RemoveAt(what_to_move);
Pnl.Children.Insert(where_to_move, btn_to_move);
}
回答2:
Try to put your items into the ItemsControl and set the wrappanel to be the ItemsPanel of the control, then just change the order of the controls inside the items control. Here is a simple example(put your control into the InputCollection).
Update #2 - DragAndDrop
Xaml
Window x:Class="WpfCSItemsControlWithWrappanelSoHelpAttempt.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid x:Name="RootLayout">
<ListBox x:Name="ListBowWithWrapPanel" Background="Green" Margin="5"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Width="250"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ListBox>
<Button HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Click="ButtonBase_OnClick">Flip</Button>
</Grid>
Code-behind(possible example of drag and drop)
public partial class MainWindow : Window
{
private readonly ObservableCollection<Shape> _observableCollection;
private int _coordinator = -1;
private ListBox _dragSource;
private Shape _dragedData;
private Shape _targetData;
private bool _isInDrag;
public MainWindow()
{
InitializeComponent();
_observableCollection = new ObservableCollection<Shape>
{
new Ellipse{Name = "C", Width = 50, Height = 50, Fill = Brushes.Tomato},
new Ellipse{Name = "A", Width = 50, Height = 75, Fill = Brushes.Yellow},
new Rectangle{Name = "Z", Width = 50, Height = 75, Fill = Brushes.Aqua},
new Rectangle{Name = "D", Width = 50, Height = 75, Fill = Brushes.Blue},
new Rectangle{Name = "B", Width = 50, Height = 75, Fill = Brushes.CadetBlue},
new Ellipse{Name = "X", Width = 75, Height = 25, Fill = Brushes.Aqua},
};
ListBowWithWrapPanel.ItemsSource = _observableCollection;
Style itemContainerStyle = new Style(typeof(ListBoxItem));
itemContainerStyle.Setters.Add(new Setter(AllowDropProperty, true));
//we have this to handle a possible dragging element
itemContainerStyle.Setters.Add(new EventSetter(PreviewMouseLeftButtonDownEvent, new MouseButtonEventHandler(ListBowWithWrapPanel_OnPreviewMouseDown)));
//we have this to start the dragging process
itemContainerStyle.Setters.Add(new EventSetter(MouseMoveEvent, new MouseEventHandler(MouseMoveHandler)));
//we have this to stop the where there is no a dragging process
itemContainerStyle.Setters.Add(new EventSetter(MouseLeftButtonUpEvent, new MouseButtonEventHandler(LeftButtonUp)));
//we have this to perform the drop(insert the element into a new position)
itemContainerStyle.Setters.Add(new EventSetter(DropEvent, new DragEventHandler(ListBowWithWrapPanel_OnDrop)));
//we have this to handle the possible target position
itemContainerStyle.Setters.Add(new EventSetter(DragOverEvent, new DragEventHandler(OnDragOver)));
ListBowWithWrapPanel.ItemContainerStyle = itemContainerStyle;
}
/// <summary>
/// sort when button click
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
var list = _observableCollection.ToList();
_observableCollection.Clear();
_coordinator *= -1;
list.Sort((shape, shape1) =>
{
var name1 = shape.Name;
var name2 = shape1.Name;
return string.Compare(name1, name2, StringComparison.Ordinal) * _coordinator;
});
list.ForEach(shape =>
{
_observableCollection.Add(shape);
});
}
/// <summary>
/// we have this to handle a possible dragging element
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ListBowWithWrapPanel_OnPreviewMouseDown(object sender, MouseButtonEventArgs e)
{
var listBoxItem = sender as ListBoxItem;
if (listBoxItem == null) return;
_dragSource = listBoxItem.FindParent<ListBox>();
_dragedData = listBoxItem.DataContext as Shape;
}
/// <summary>
/// we have this to start the dragging process
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void MouseMoveHandler(object sender, MouseEventArgs e)
{
if (_dragedData != null && _isInDrag == false)
{
_isInDrag = true;
DragDrop.DoDragDrop(_dragSource, _dragedData, DragDropEffects.Move);
}
}
/// <summary>
/// we have this to handle the possible target position
/// </summary>
/// <param name="sender"></param>
/// <param name="dragEventArgs"></param>
private void OnDragOver(object sender, DragEventArgs dragEventArgs)
{
var targetPlaceHolder = sender as ListBoxItem;
if (targetPlaceHolder == null) return;
_targetData = targetPlaceHolder.DataContext as Shape;
}
/// <summary>
/// we have this to stop where there is no a dragging process
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void LeftButtonUp(object sender, MouseButtonEventArgs e)
{
ResumeDragging();
}
/// <summary>
/// we have this to perform the drop(insert the element into a new position)
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ListBowWithWrapPanel_OnDrop(object sender, DragEventArgs e)
{
if (Equals(_dragedData, _targetData)) return;
var targetPlaceHolder = sender as ListBoxItem;
if (targetPlaceHolder == null) return;
var removedIdx = _observableCollection.IndexOf(_dragedData);
var targetIdx = _observableCollection.IndexOf(_targetData);
if (removedIdx < targetIdx)
{
_observableCollection.Insert(targetIdx + 1, _dragedData);
_observableCollection.RemoveAt(removedIdx);
}
else
{
int remIdx = removedIdx + 1;
if (_observableCollection.Count + 1 > remIdx)
{
_observableCollection.Insert(targetIdx, _dragedData);
_observableCollection.RemoveAt(remIdx);
}
}
ResumeDragging();
}
private void ResumeDragging()
{
_isInDrag = false;
_dragedData = null;
}
}
Regards.
来源:https://stackoverflow.com/questions/36642622/rearrange-customcontrol-inside-wrappanel-in-wpf-c-sharp