Rearrange CustomControl inside wrappanel in wpf c#

旧城冷巷雨未停 提交于 2019-12-22 17:48:44

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!