There is a button

<Button Width="100" Height="24" Header="ОК" x:Name="okButton"/> 

Somewhere in the code, I change the Width of this button.

 okButton.Width = 200; 

How to create a smooth resize animation? Those. How to attach an animation to the Width field, so that no matter where I change its value in the code, did the animation work?

  • Do you need a button, or is UserControl suitable? - VladD
  • UserControl is even better - MaximK

2 answers 2

I did it like this: catch the change in the width of UserControl 'a, and start the animation of the width of the content.

In this case, however, the reduced width of UserControl 'and' cuts off 'slowly decreasing parts of the content, so you have to turn off clipping manually.

Control:

 <UserControl x:Class="SlowWidthChanging.SlowResizingControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:SlowWidthChanging"> <local:NoClipGrid x:Name="InnerPart" HorizontalAlignment="Center" Width="{Binding ActualWidth, RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}"> <Button>Привет, мир!</Button> </local:NoClipGrid> </UserControl> 
 public partial class SlowResizingControl : UserControl { static DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(SlowResizingControl.WidthProperty, typeof(SlowResizingControl)); public SlowResizingControl() { InitializeComponent(); Loaded += (o, args) => { dpd.AddValueChanged(this, OnWidthChanged); OnWidthChanged(this, null); }; // обязательно отписаться, чтобы избежать утечки памяти Unloaded += (o, args) => dpd.RemoveValueChanged(this, OnWidthChanged); } void OnWidthChanged(object self, EventArgs args) { InnerPart.BeginAnimation( Grid.WidthProperty, new DoubleAnimation( toValue: this.Width, duration: new Duration(TimeSpan.FromSeconds(0.5)), fillBehavior: FillBehavior.Stop)); } } 

Well, the auxiliary class ( from here ):

 class NoClipGrid : Grid { protected override Geometry GetLayoutClip(Size layoutSlotSize) { return null; } } 

You can test:

 <Window x:Class="SlowWidthChanging.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:SlowWidthChanging" Height="350" Width="525"> <Grid x:Name="OuterContainer"> <local:SlowResizingControl Height="50" Width="100" x:Name="SizeChangeTarget"/> <Button Width="150" Height="25" Content="Поменять ширину" Click="ChangeButtonSize" VerticalAlignment="Bottom" Margin="10"/> </Grid> </Window> 
 public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } void ChangeButtonSize(object sender, RoutedEventArgs e) { double newWidth = (double.IsNaN(SizeChangeTarget.Width) || SizeChangeTarget.Width == 100) ? 200 : 100; SizeChangeTarget.Width = newWidth; } } 

    Here you can try to use event triggers. For example, something like this:

     <EventTrigger RoutedEvent="Button.Click"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetName="okButton" Storyboard.TargetProperty="Width" From="75" To="200" Duration="0:0:2" /> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> 

    Or write the animation in the form of a "normal" code in some method:

     DoubleAnimation buttonAnimation = new DoubleAnimation(); //Начальное и конечное значение buttonAnimation.From = okButton.ActualWidth; buttonAnimation.To = 200; //Продолжительность анимации buttonAnimation.Duration = TimeSpan.FromSeconds(3); //Запуск анимации okButton.BeginAnimation(Button.WidthProperty, buttonAnimation); 
    • It uses the event of the Click button itself; I think it will not work - MaximK