DragEnter& DragLeave:避免在自定义拖动预览上出现令人讨厌的闪烁

时间:2013-11-11 16:12:53

标签: c# wpf drag-and-drop mvvm-light

我已经实施了一个小WPF应用程序将动物从商店拖到我的谷仓。 ; - )

我正在使用:

  • MVVMlight及其EventToCommand行为
  • 动物是一个简单的Border聆听MouseDown
  • 该谷仓是ItemsControl绑定到ViewModel的ObservableCollection。它听3个事件:
    • DragEnter(将假动物添加到ObservableCollection以预览动物放置在谷仓的位置)
    • DragLeave(如果动物未掉落,则移除假动物)
    • Drop(将动物设置在谷仓中的指定位置)。

对不起。我没有上传图片的声誉。所以我尝试了一些ascii arts(尝试将驴拖入谷仓):

Shop   | Barn
-------------------------
Mouse  | [Mouse] [Dog] 
Cat    | [.]
Dog    |  ^
Donkey-|--|

问题在于:

如果我将动物拖入谷仓的指定空间(预览假人):

  1. DragLeave删除虚拟项目并立即删除
  2. DragEnter将被解雇以重绘虚拟物品。转到第1步。
  3. 一个inifite循环。闪烁正在运行!

    有没有人知道一个不错的小解决方法?

    所以这是我的ViewModel的代码:

    private string _dummy;
    public ObservableCollection<string> Animals { get; private set; }
    
    private void StartDrag(FrameworkElement element)
    {
        var animal = element.DataContext as string;
        if (animal == null) return;
        System.Windows.DragDrop.DoDragDrop(element, animal, DragDropEffects.Copy);
    }
    
    private void PreviewDrop(DragEventArgs args)
    {
        if (args.Data.GetDataPresent(typeof (string)))
            AddDummy();
    }
    
    private void StopDrop(DragEventArgs args)
    {
        RemoveDummy();
    }
    
    private void Drop(DragEventArgs args)
    {
        var animal = args.Data.GetData(typeof (string)) as string;
        if (animal == null) return;
    
        RemoveDummy();
        Animals.Add(animal);
    }
    
    private void RemoveDummy()
    {
        if (_dummy == null) return;
        Animals.Remove(_dummy);
        _dummy = null;
    }
    
    private void AddDummy()
    {
        if (_dummy != null) return;
        _dummy = ".";
        Animals.Add(_dummy);
    }
    

    感谢您的帮助

    马塞尔

2 个答案:

答案 0 :(得分:3)

好的,我明白了。 IsHitTestVisible可以解决问题!这是两个解决方案:

第一种方法,快捷方式: 只需将所有动物放入谷仓(通过修改目标ItemTemplate中的ItemsControl)至IsHitTestVisible="False"

<ItemsControl.ItemTemplate>
    <DataTemplate DataType="{x:Type system:String}">
        <Border Background="Gray" IsHitTestVisible="False">
            <TextBlock Text="{Binding}" Foreground="White" />
        </Border>
    </DataTemplate>
</ItemsControl.ItemTemplate>

因此,每个项目仍然可见,但项目和ItemsControl都没有触发任何事件。可是等等!如果我想通过将新动物拖到旧动物上来取代动物怎么办?我至少需要一个适当的Drop事件?

第二种方法,更好的方法: 我将IsHitTestVisible="False" 设置为虚拟动物(此处我将字符串内容与"."进行比较,以检查它是否为假人)。

<ItemsControl.ItemTemplate>
    <DataTemplate DataType="{x:Type system:String}">
        <Border Name="AnimalPlace" Background="Gray">
            <TextBlock Text="{Binding}" Foreground="White" />
        </Border>
        <DataTemplate.Triggers>
            <DataTrigger Binding="{Binding}" Value=".">
                <Setter TargetName="AnimalPlace" Property="IsHitTestVisible" Value="False" />
            </DataTrigger>
        </DataTemplate.Triggers>
    </DataTemplate>
</ItemsControl.ItemTemplate>

最后一种方法适用于MVVM方面,完全符合我的需求。更不用说它可以很容易地适应更复杂的对象(比表示动物的字符串更复杂)。

我现在很开心: - )

答案 1 :(得分:0)

简单的解决方案,您可能只需要使用标志来控制DragLeaveDragEnter代码执行。检查Here以了解事件的顺序