2017-10-20 19 views
0

J'essaie de créer un contrôle utilisateur qui peut redimensionner et réduire/développer (avec une animation). Le redimensionnement cesse de fonctionner lorsque je joue l'animation Réduire/Agrandir.Problème WPF avec une commande utilisateur redimensionnable/réductible

application de test complète se trouve ici: App

EDIT: voici le code correspondant à la demande

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> 

MyContr ol.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; 
     } 
    } 
} 

Merci pour l'aide :)

+0

Vous devez coller les codes clés ici afin que d'autres puissent obtenir rapidement le problème. Cela peut aussi aider ceux qui ont les mêmes problèmes. – Iron

+0

Avez-vous utilisé le story-board? Il existe une propriété Fill qui peut être définie sur Hold of Stop. Si vous conservez le comportement Hold par défaut, DependencyProperty sera mis à jour par le storyboard même lorsque la valeur finale est atteinte. – Dmitry

+0

Vous voulez modifier la propriété une fois le storyboard terminé? – Iron

Répondre

1

L'animation ne s'arrête jamais. Vous devez spécifier FillBehavior to Stop. Dans ce cas, l'annimation arrêtera la mise à jour de la propriété une fois la valeur finale atteinte.

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; 
    } 

La valeur par défaut est HoldEnd. Et le storyboard modifiera la largeur jusqu'à ce qu'elle ne soit pas explicitement arrêtée.

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

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

+0

Je suis allé avec la même solution :) Je ne connaissais pas le FillBehavior, donc merci pour celui-ci :) – Sugz

0

Eh bien merci à idée Dmitry, que je suis en mesure de le résoudre, en définissant le comportement de remplissage d'arrêter et de forcer à largeur à 0 ou l'ouverture largeur:

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); 

} 

Merci à tous :)