简体   繁体   English

龚解决方案拖放以对列表进行排序,从列表中删除项目

[英]Gong Solutions Drag and Drop to sort a list removing items from the list

I am trying to get my Gong Solutions drag and drop to sort a single list.我试图让我的龚解决方案拖放以对单个列表进行排序。 When I drag an item and drop it, it removes the item from the list and I can see it disappear from the interface.当我拖放一个项目时,它会从列表中删除该项目,我可以看到它从界面中消失了。 It appears that the DragOver method is not moving the object first, so when the Drop method fires off, it simply removes the item.看起来DragOver方法不是先移动对象,所以当Drop方法触发时,它只是删除项目。

When I remove the attribute dd:DragDrop.DropHandler="{Binding}" , the drag and drop on the interface works fine.当我删除属性dd:DragDrop.DropHandler="{Binding}" ,界面上的拖放工作正常。 However, I have to have an event fire so i know when the list has been re-ordered.但是,我必须有一个事件触发,所以我知道列表何时被重新排序。

XAML: XAML:

<Window x:Class="Reorder_item_WPF.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" 
        xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
        xmlns:dd="clr-namespace:GongSolutions.Wpf.DragDrop;assembly=GongSolutions.Wpf.DragDrop">
    <Grid>
        <ListBox Grid.Column="1" SelectionMode="Extended" ItemsSource="{Binding MSPCollection}"
                 dd:DragDrop.IsDragSource="True" Width="300" Margin="0,0,5,0" 
                 dd:DragDrop.IsDropTarget="True"
                 dd:DragDrop.DropHandler="{Binding}">

            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Grid Background="#2ba3d5" Height="50" Width="280">
                        <TextBlock Drop="TextBlock_Drop" Text="{Binding Name}" 
                                   Foreground="White" 
                                   HorizontalAlignment="Center" 
                                   VerticalAlignment="Center" 
                                   FontSize="40"/>
                    </Grid>                    
                </DataTemplate>             
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>

C#: C#:

public class MSP {
    public int Id { get; set; }
    public string Name { get; set; }        
}

class MainViewModel : IDropTarget
{
    public ObservableCollection<MSP> MSPCollection { get; set; }

    public MainViewModel() {
        MSPCollection = new ObservableCollection<MSP>();

        MSPCollection.Add(new MSP() { 
            Id = 1,
            Name = "Anis Derbel"
        });

        MSPCollection.Add(new MSP()
        {
            Id = 2,
            Name = "Firas Mdimagh"
        });

        MSPCollection.Add(new MSP()
        {
            Id = 3,
            Name = "Khaled Jemni"
        });

        MSPCollection.Add(new MSP()
        {
            Id = 4,
            Name = "Sahbouch"
        });        
    }

    public void DragOver(IDropInfo dropInfo) {
        if (dropInfo.Data is MSP) {
            dropInfo.DropTargetAdorner = DropTargetAdorners.Highlight;
            dropInfo.Effects = DragDropEffects.Move;
        }
    }

    public void Drop(IDropInfo dropInfo) {
        MSP msp = (MSP)dropInfo.Data;
        ((IList)dropInfo.DragInfo.SourceCollection).Remove(msp);
    }
}

DragOver does not remove any items. DragOver不会删除任何项目。 You're removing the items in the Drop method.您正在删除Drop方法中的项目。 You should not be doing any removing or adding in the DragOver method, that's what the Drop method is for.您不应该在DragOver方法中进行任何删除或添加操作,这就是Drop方法的用途。 DragOver should only be used to set the target adorner and effects. DragOver应该只用于设置目标装饰器和效果。 I used ILSpy to look at their code (see below), and that helped shed some light on what's happening here.我使用 ILSpy 查看他们的代码(见下文),这有助于了解这里发生的事情。 They have a class called DefaultDropHandler : IDropTarget , which, as the name implies, is the default drop handler if one is not assigned using the attached property dd:DragDrop.DropHandler .它们有一个名为DefaultDropHandler : IDropTarget的类DefaultDropHandler : IDropTarget ,顾名思义,如果未使用附加属性dd:DragDrop.DropHandler分配,则它是默认放置处理程序。 So when you delete the line dd:DragDrop.DropHandler="{Binding}" , that is what is used for the drop operation.因此,当您删除dd:DragDrop.DropHandler="{Binding}"行时,这就是用于放置操作的内容。 Looking at their code, everything is handled for your, that is the item is added and removed, with a whole slew of error checking and index control along the way.查看他们的代码,一切都为您处理,即添加和删除项目,并在此过程中进行大量错误检查和索引控制。

When you do indeed set the drop handler to be your ViewModel, none of the code in the default handler executes, as you replaced that handler with your ViewModel.当您确实将放置处理程序设置为您的 ViewModel 时,默认处理程序中的任何代码都不会执行,因为您将该处理程序替换为您的 ViewModel。 Thus, you must fully handle the drop.因此,您必须完全处理掉落。 In other words, you have to do all the error and type checking, removing items and adding items (if you have more than one list), and keeping the correct order.换句话说,您必须进行所有错误和类型检查、删除项目和添加项目(如果您有多个列表),并保持正确的顺序。 You may also want to check that the source collection is not the same as the target collection before you do any of the removing and adding, but this will still not add them into the correct positions.在执行任何删除和添加操作之前,您可能还想检查源集合是否与目标集合不同,但这仍然不会将它们添加到正确的位置。

Since you have only one list, do not remove the item in Drop method.由于您只有一个列表,因此不要在Drop方法中删除该项目。 But, nothing will happen for the reasons I stated above.但是,由于我上面提到的原因,什么都不会发生。 If you do have more than one list, here's how you would make the items move from one list to another:如果您确实有多个列表,以下是使项目从一个列表移动到另一个列表的方法:

public void Drop(IDropInfo dropInfo) 
{
    MSP msp = (MSP)dropInfo.Data;
    if(dropInfo.DragInfo.SourceCollection != dropInfo.TargetCollection)
    {
        ((IList)dropInfo.DragInfo.SourceCollection).Remove(msp);
        ((IList)dropInfo.TargetCollection).Add(msp);
    }
}

You will have to do the work of keeping the items in the correct order, if that is what you require.如果这是您的要求,您将不得不按照正确的顺序进行保存。 As an alternative to doing all this work, you can leverage and extend their default handler.作为完成所有这些工作的替代方法,您可以利用和扩展它们的默认处理程序。 They made Drop method virtual , so you can make your view model inherit from DefaultDropHandler他们将Drop方法virtual ,因此您可以使您的视图模型继承自DefaultDropHandler
(ie class MainViewModel : DefaultDropHandler ) rather than implementing the IDropTarget interface. (即class MainViewModel : DefaultDropHandler )而不是实现IDropTarget接口。 Then, simply override the Drop method, and call to the base method.然后,只需覆盖Drop方法,并调用基本方法。 Something like this:像这样的东西:

public override void Drop(IDropInfo dropInfo)
{
    base.Drop(dropInfo);
    //do other stuff
}

You can also override the DragOver method in the same way if you need to, but if you don't, it will just use the default behaviour.如果需要,您也可以以相同的方式覆盖DragOver方法,但如果不这样做,它将只使用默认行为。

Extra Info额外信息

If you're curious, here's the default handler that Gong uses when you don't assign one:如果你很好奇,这里是当你没有分配一个时,Gong 使用的默认处理程序:

public virtual void Drop(IDropInfo dropInfo)
{
    if (dropInfo != null && dropInfo.DragInfo != null)
    {
        int insertIndex = (dropInfo.InsertIndex != dropInfo.UnfilteredInsertIndex) ? dropInfo.UnfilteredInsertIndex : dropInfo.InsertIndex;
        ItemsControl itemsControl = dropInfo.VisualTarget as ItemsControl;
        if (itemsControl != null)
        {
            IEditableCollectionView editableItems = itemsControl.Items;
            if (editableItems != null)
            {
                NewItemPlaceholderPosition newItemPlaceholderPosition = editableItems.NewItemPlaceholderPosition;
                if (newItemPlaceholderPosition == NewItemPlaceholderPosition.AtBeginning && insertIndex == 0)
                {
                    insertIndex++;
                }
                else if (newItemPlaceholderPosition == NewItemPlaceholderPosition.AtEnd && insertIndex == itemsControl.Items.Count)
                {
                    insertIndex--;
                }
            }
        }
        IList destinationList = dropInfo.TargetCollection.TryGetList();
        List<object> data = ExtractData(dropInfo.Data).OfType<object>().ToList();
        List<object>.Enumerator enumerator;
        if (!ShouldCopyData(dropInfo))
        {
            IList sourceList = dropInfo.DragInfo.SourceCollection.TryGetList();
            if (sourceList != null)
            {
                enumerator = data.GetEnumerator();
                try
                {
                    while (enumerator.MoveNext())
                    {
                        object o2 = enumerator.Current;
                        int index = sourceList.IndexOf(o2);
                        if (index != -1)
                        {
                            sourceList.RemoveAt(index);
                            if (destinationList != null && object.Equals(sourceList, destinationList) && index < insertIndex)
                            {
                                insertIndex--;
                            }
                        }
                    }
                }
                finally
                {
                    ((IDisposable)enumerator).Dispose();
                }
            }
        }
        if (destinationList != null)
        {
            TabControl tabControl = dropInfo.VisualTarget as TabControl;
            bool cloneData = dropInfo.Effects.HasFlag(DragDropEffects.Copy) || dropInfo.Effects.HasFlag(DragDropEffects.Link);
            enumerator = data.GetEnumerator();
            try
            {
                while (enumerator.MoveNext())
                {
                    object o = enumerator.Current;
                    object obj2Insert = o;
                    if (cloneData)
                    {
                        ICloneable cloneable = o as ICloneable;
                        if (cloneable != null)
                        {
                            obj2Insert = cloneable.Clone();
                        }
                    }
                    destinationList.Insert(insertIndex++, obj2Insert);
                    if (tabControl != null)
                    {
                        TabItem obj = tabControl.ItemContainerGenerator.ContainerFromItem(obj2Insert) as TabItem;
                        if (obj != null)
                        {
                            obj.ApplyTemplate();
                        }
                        tabControl.SetSelectedItem(obj2Insert);
                    }
                }
            }
            finally
            {
                ((IDisposable)enumerator).Dispose();
            }
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM