如何使此放置叠加的淡入动画效果良好?

时间:2019-06-19 12:26:21

标签: wpf animation drag-and-drop

我有一个简单的MainWindow,它带有一个包含Grid的根网格和一个带有Button的单元格,并且根网格还包含一个overlay控件(该控件具有部分透明的背景和一些短文字,例如Drop here ...) 。当用户在窗口上拖动文件时,此全窗口叠加层会以淡入淡出的动画显示。问题是我的动画没有完成,几乎没有开始,并在用户将文件拖到窗口上时重复播放。

我不确定下一步要去哪里。 DropOverlay类和XAML看起来不错。我认为问题出在d&d事件处理中。当我使用IsHitTestVisible =“ False”时,如果没有动画,它似乎会更好地工作。

DropOverlay

XAML

<UserControl x:Class="cs_wpf_test_16.DropOverlay"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:cs_wpf_test_16"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800"
             Style="{DynamicResource BorderStyle1}">
    <UserControl.Resources>
        <Style TargetType="UserControl" x:Key="BorderStyle1">
            <Style.Triggers>
                <Trigger Property="Visibility" Value="Visible">
                    <Trigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:0.5">
                                </DoubleAnimation>
                            </Storyboard>
                        </BeginStoryboard>
                    </Trigger.EnterActions>
                    <Trigger.ExitActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.5">
                                </DoubleAnimation>
                            </Storyboard>
                        </BeginStoryboard>
                    </Trigger.ExitActions>
                </Trigger>
            </Style.Triggers>
        </Style>
    </UserControl.Resources>
    <Border Background="#99000000">
        <Viewbox>
            <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center"
                        Orientation="Horizontal" Margin="100" IsHitTestVisible="False">
                <TextBlock Foreground="White" FontSize="50" Margin="15,0,0,0" Name="MyTextBlock">Drop Here...</TextBlock>
            </StackPanel>
        </Viewbox>
    </Border>
</UserControl>

隐藏代码

没什么特别的。

MainWindow

XAML

<Window x:Class="cs_wpf_test_16.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:cs_wpf_test_16"
        mc:Ignorable="d"
        Title="MainWindow" Height="209.375" Width="317.969"
        PreviewDragEnter="MyWindow_DragEnter"
        PreviewDragLeave="MyWindow_DragLeave"
        PreviewDrop="MyWindow_Drop"
        AllowDrop="True">
    <Grid>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>

            <Button>Test</Button>
        </Grid>
        <local:DropOverlay Visibility="Collapsed" x:Name="MyDropOverlay"/>
    </Grid>
</Window>

隐藏代码

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    internal bool _DraggingOver = false;
    internal bool DraggingOver
    {
        get
        {
            return _DraggingOver;
        }
        set
        {
            if (_DraggingOver != value)
            {
                _DraggingOver = value;
                UpdateDropIndicator();
            }
        }
    }

    private void UpdateDropIndicator()
    {
        if (DraggingOver)
        {
            MyDropOverlay.Visibility = Visibility.Visible;
        }
        else
        {
            MyDropOverlay.Visibility = Visibility.Collapsed;
        }
    }

    private void MyWindow_DragEnter(object sender, DragEventArgs e)
    {
        if (e.Data.GetDataPresent(DataFormats.FileDrop) &&
            !(e.Source is DropOverlay))
        {
            e.Effects = DragDropEffects.Link;

            var paths = e.Data.
                GetData(DataFormats.FileDrop) as string[];

            string path = paths[0];

            DraggingOver = true;

            e.Handled = true;
        }
        else
        {
            DraggingOver = false;

            //e.Handled = true;
        }
    }

    private void MyWindow_Drop(object sender, DragEventArgs e)
    {
        if (GetVisualParent<DropOverlay>(e.Source) == null)
        {
            e.Handled = true;
            return;
        }

        string[] paths = null;

        if (e.Effects != DragDropEffects.None &&
            e.Data.GetDataPresent(DataFormats.FileDrop))
        {
            paths = e.Data.
                GetData(DataFormats.FileDrop) as string[];
        }

        DraggingOver = false;

        if (paths != null)
        {
            MessageBox.Show(this, "Dropped.");
            e.Handled = true;
        }
    }

    private void MyWindow_DragLeave(object sender, DragEventArgs e)
    {
        if (GetVisualParent<DropOverlay>(e.Source) == null)
        {
            e.Handled = true;
            return;
        }

        Point p = Mouse.GetPosition(this);
        if (p.X < 0 || p.Y < 0 ||
            p.X > ActualWidth || p.Y > ActualHeight)
        {
            DraggingOver = false;

            e.Handled = true;
        }
    }

    public static T GetVisualParent<T>(object childObject) where T : System.Windows.Media.Visual
    {
        var child = childObject as System.Windows.DependencyObject;
        // iteratively traverse the visual tree
        while ((child != null) && !(child is T))
        {
            child = System.Windows.Media.VisualTreeHelper.GetParent(child);
        }
        return child as T;
    }
}

预期结果:当用户开始在窗口上拖动文件时,淡入动画将运行并结束一次。

实际结果:淡入动画没有结束,它一遍又一遍地开始,一直运行到几乎看不到覆盖层的位置。有时候,当我用鼠标离开窗口并拖动叠加层时,它会很好地淡入(但不是在适当的时候),有时不是。

屏幕截图

screenshot with the problem

screenshot with the drop overlay

1 个答案:

答案 0 :(得分:1)

发现它只是删除您在 MyWindow_DragEnter

中的其他情况

复制下面的代码,然后粘贴而不是MyWindow_DragEnter方法。

如果你很懒:)

    private void MyWindow_DragEnter(object sender, DragEventArgs e)
    {
        if (e.Data.GetDataPresent(DataFormats.FileDrop) &&
            !(e.Source is DropOverlay))
        {
            e.Effects = DragDropEffects.Link;

            var paths = e.Data.
                GetData(DataFormats.FileDrop) as string[];

            string path = paths[0];

            DraggingOver = true;

            e.Handled = true;
        }

    }

用于淡入/淡出动画

问题是动画时您的UserControl设置为“折叠” =>我们需要“连接的动画”(一个接一个的动画)

在我们的情况下,我们需要一些独立的布尔值:我选择了Selector.IsSelected。

更改您的UpdateDropIndicator方法


        private void UpdateDropIndicator()
        {
            if (DraggingOver)
            {
                Selector.SetIsSelected(MyDropOverlay, true);
                //   MyDropOverlay.Visibility = Visibility.Visible;
            }
            else
            {
                Selector.SetIsSelected(MyDropOverlay, false);
                //MyDropOverlay.Visibility = Visibility.Collapsed;
            }
        }

和您的xaml动画


             <Trigger Property="Selector.IsSelected" Value="True">
                    <Trigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation Storyboard.TargetProperty="Opacity" 
                                                 From="0" 
                                                 To="1" 
                                                 Duration="0:0:0.5"/>
                                <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility"
                                                               Duration="0:0:0">
                                    <DiscreteObjectKeyFrame Value="{x:Static Visibility.Visible}" />
                                </ObjectAnimationUsingKeyFrames>
                            </Storyboard>
                        </BeginStoryboard>
                    </Trigger.EnterActions>
                    <Trigger.ExitActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation Storyboard.TargetProperty="Opacity" 
                                                 From="1" 
                                                 To="0" 
                                                 Duration="0:0:0.5"/>
                                <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility"
                                                               Duration="0:0:0.5">
                                    <DiscreteObjectKeyFrame Value="{x:Static Visibility.Collapsed}" />
                                </ObjectAnimationUsingKeyFrames>
                            </Storyboard>
                        </BeginStoryboard>
                    </Trigger.ExitActions>
                </Trigger>