wpf 如何在从可视树中移除元素之前执行一些代码?

bt1cpqcv  于 12个月前  发布在  其他
关注(0)|答案(1)|浏览(110)

我试图实现一些淡入和淡出动画的用户控件在WPF。对于淡入动画,我可以使用Loaded事件来完成。

public sealed partial class NowPlayingView : UserControl
    {
        public Duration AnimationDuration
        {
            get { return (Duration)GetValue(AnimationDurationProperty); }
            set { SetValue(AnimationDurationProperty, value); }
        }

        public static readonly DependencyProperty AnimationDurationProperty =
            DependencyProperty.Register("AnimationDuration", typeof(Duration), typeof(NowPlayingView), new PropertyMetadata(Duration.Automatic));

        public NowPlayingView()
        {
            Opacity = 0;
            InitializeComponent();
            Loaded += NowPlayingView_Loaded;
            Unloaded += NowPlayingView_Unloaded;

        }

        private void NowPlayingView_Unloaded(object sender, RoutedEventArgs e)
        {
            DoubleAnimation animation = new(1.0, 0.0, AnimationDuration);
            BeginAnimation(OpacityProperty, animation);
        }

        private void NowPlayingView_Loaded(object sender, RoutedEventArgs e)
        {
            DoubleAnimation animation = new (0.0, 1.0, AnimationDuration);
            BeginAnimation(OpacityProperty, animation);
        }
    }

我尝试使用Unloaded事件来实现淡出效果,结果发现该事件是在**从可视树中删除UserControl之后(当UserControl不再可见或不可访问时)触发的。有没有办法在UserControl“关闭”之前运行一些代码,比如WindowOnClosing事件?

编辑:

对于更多的上下文,UserControl充当更复杂窗口的组件。当属性NowPlayingViewModel不为空时,它被激活,当为空时,它被停用(我这样做是为了隐藏UserControl)。当我将ViewModel设置为null时,我希望运行淡出动画,并且我希望保持代码隐藏与其他ViewModel逻辑的解耦。

<!-- Now playing View-->
<ContentControl Grid.RowSpan="3" Grid.ColumnSpan="2" Content="{Binding NowPlayingViewModel}">
    <ContentControl.Resources>
        <DataTemplate DataType="{x:Type viewmodels:NowPlayingViewModel}">
            <views:NowPlayingView AnimationDuration="00:00:00.8" />
        </DataTemplate>
    </ContentControl.Resources>
</ContentControl>

从我的测试中,到目前为止我还没有找到任何好的解决方案,尽管我愿意接受导致类似行为的建议。

pftdvrlh

pftdvrlh1#

我找到了一个更简单、更优雅的解决方案。

public sealed partial class NowPlayingView : UserControl
    {
        private bool _animating = false;

        public bool ShowWindow
        {
            get { return (bool)GetValue(ShowWindowProperty); }
            set { SetValue(ShowWindowProperty, value); }
        }

        public static readonly DependencyProperty ShowWindowProperty =
            DependencyProperty.Register("ShowWindow", typeof(bool), typeof(NowPlayingView), new PropertyMetadata(false, OnShowWindowChanged));

        private static void OnShowWindowChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is NowPlayingView userControl && (bool)e.NewValue == true)
                userControl.Show();            
        }

        public NowPlayingView()
        {
            InitializeComponent();
            Opacity = 0;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            _animating = true;

            Hide();

            _animating = false;
        }

        private void Show()
        {
            Visibility = Visibility.Visible;

            DoubleAnimation animation = new()
            {
                From = 0.0,
                To = 1.0,
                FillBehavior = FillBehavior.HoldEnd,
                Duration = new(TimeSpan.FromMilliseconds(600))
            };
            Storyboard storyboard = new();

            storyboard.Children.Add(animation);
            Storyboard.SetTarget(animation, this);
            Storyboard.SetTargetProperty(animation, new PropertyPath(OpacityProperty));
            storyboard.Begin();
        }

        private void Hide()
        {
            DoubleAnimation animation = new()
            {
                From = 1.0,
                To = 0.0,
                FillBehavior = FillBehavior.Stop,
                Duration = new(TimeSpan.FromMilliseconds(600))
            };
            Storyboard storyboard = new();

            storyboard.Children.Add(animation);
            Storyboard.SetTarget(animation, this);
            Storyboard.SetTargetProperty(animation, new PropertyPath(OpacityProperty));
            storyboard.Completed += delegate 
            { 
                Visibility = Visibility.Collapsed; 
            };
            storyboard.Begin();
        }
    }

我创建了一个依赖项属性ShowWindow。每当属性更改为true时,它将触发淡入动画的故事板。对于淡出,我只是挂接了一个按钮OnClick事件,但我也可以在DependencyPropertyChanged方法中轻松完成。
这样我就保持了代码的解耦,并直接从ViewModel控制UserControl的动画,该ViewModel具有绑定到UserControl上的ShowWindow依赖项属性的属性。

相关问题