带有可调整大小/可折叠用户控件的WPF问题

时间:2017-10-20 12:36:27

标签: wpf animation resize controls

我正在尝试创建一个可以调整大小和折叠/展开的用户控件(带动画)。当我播放折叠/展开动画时,调整大小停止工作。

完整的测试应用程序可在此处找到:App

编辑:这是所要求的相关代码

MyControl.xaml:

<UserControl x:Class="WpfApp1.MyControl"
         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:WpfApp1"
         mc:Ignorable="d" 
         d:DesignHeight="300" 
         d:DesignWidth="300">

<Grid Background="#FF935E5E">
    <Thumb Width="8"
           HorizontalAlignment="Right"
           Margin="0,0,-4,0"
           DragDelta="Thumb_DragDelta" 
           Cursor="SizeWE"/>
</Grid>

MyControl.xaml.cs:

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Animation;

namespace WpfApp1
{
    /// <summary>
    /// Interaction logic for MyControl.xaml
    /// </summary>
    public partial class MyControl : UserControl
    {

        public bool IsOpen
        {
            get { return (bool)GetValue(IsOpenProperty); }
            set { SetValue(IsOpenProperty, value); }
        }
        public static readonly DependencyProperty IsOpenProperty =
            DependencyProperty.Register("IsOpen", typeof(bool), typeof(MyControl), new PropertyMetadata(true, OnIsOpenChanged));

        private static void OnIsOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            MyControl control = d as MyControl;
            control.PlayAnimation();
        }



        public double OpenWidth
        {
            get { return (double)GetValue(OpenWidthProperty); }
            set { SetValue(OpenWidthProperty, value); }
        }
        public static readonly DependencyProperty OpenWidthProperty =
            DependencyProperty.Register("OpenWidth", typeof(double), typeof(MyControl), new PropertyMetadata(300d, OnOpenWidthChanged));

        private static void OnOpenWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            MyControl control = d as MyControl;
            if (control.IsOpen)
                control.Width = control.OpenWidth;
        }



        public MyControl()
        {
            InitializeComponent();
            if (IsOpen)
                Width = OpenWidth;
        }

        private void Thumb_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
        {
            OpenWidth += e.HorizontalChange;
        }


        private void PlayAnimation()
        {
            DoubleAnimation sizeAnimation = new DoubleAnimation(IsOpen ? OpenWidth : 0, TimeSpan.FromMilliseconds(250));
            sizeAnimation.EasingFunction = new CircleEase() { EasingMode = EasingMode.EaseInOut };
            BeginAnimation(WidthProperty, sizeAnimation);

        }
    }
}

MainWindow.xaml:

<Window x:Class="WpfApp1.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:WpfApp1"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="700">

<DockPanel>
    <local:MyControl IsOpen="{Binding ControlIsOpen}"
                     OpenWidth="{Binding ControlOpenWidth}"/>
    <Grid Background="Green">
        <Button Width="100"
                Height="20"
                Content="Test Animation" 
                Click="Button_Click"/>
    </Grid>
</DockPanel>

MainWindow.xaml.cs:

using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;

namespace WpfApp1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        #region INotifyPropertyChanged

        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged([CallerMemberName] string propertyName = null) =>
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

        #endregion INotifyPropertyChanged


        private bool _ControlIsOpen = true;
        public bool ControlIsOpen
        {
            get => _ControlIsOpen;
            set
            {
                _ControlIsOpen = value;
                OnPropertyChanged();
            }
        }


        private double _ControlOpenWidth = 300d;
        public double ControlOpenWidth
        {
            get => _ControlOpenWidth;
            set
            {
                _ControlOpenWidth = value;
                OnPropertyChanged();
            }
        }



        public MainWindow()
        {
            InitializeComponent();
            DataContext = this;
        }


        private void Button_Click(object sender, RoutedEventArgs e)
        {
            ControlIsOpen = !ControlIsOpen;
        }
    }
}

感谢您的帮助:)

2 个答案:

答案 0 :(得分:1)

动画实际上永远不会停止你应该指定FillBehavior停止。在这种情况下,annimation将在达到最终值后停止更新属性。

    private void PlayAnimation()
    {
        DoubleAnimation sizeAnimation = new DoubleAnimation(IsOpen ? OpenWidth : 0, TimeSpan.FromMilliseconds(250));
        sizeAnimation.FillBehavior = FillBehavior.Stop;
        sizeAnimation.EasingFunction = new CircleEase() { EasingMode = EasingMode.EaseInOut };
        sizeAnimation.Completed += OnAnimationCompleted;
        BeginAnimation(WidthProperty, sizeAnimation);

    }

    private void OnAnimationCompleted(object sender, EventArgs e)
    {
        Width = IsOpen ? OpenWidth : 0;
    }

默认值为HoldEnd。故事板将修改宽度,直到它没有明确停止。

https://msdn.microsoft.com/en-us/library/system.windows.media.animation.timeline.fillbehavior(v=vs.110).aspx

更多信息https://docs.microsoft.com/en-us/dotnet/framework/wpf/graphics-multimedia/how-to-set-a-property-after-animating-it-with-a-storyboard

答案 1 :(得分:0)

非常感谢德米特里的想法,我已经能够解决它,通过设置填充行为来停止并强制宽度为0或开放宽度:

private void PlayAnimation()
{
    DoubleAnimation sizeAnimation = new DoubleAnimation(IsOpen ? OpenWidth : 0, TimeSpan.FromMilliseconds(250));
    sizeAnimation.EasingFunction = new CircleEase() { EasingMode = EasingMode.EaseInOut };
    sizeAnimation.FillBehavior = FillBehavior.Stop;
    sizeAnimation.Completed += (s, e) => Width = (IsOpen ? OpenWidth : 0);
    BeginAnimation(WidthProperty, sizeAnimation);

}

全部谢谢:)