简体   繁体   中英

WPF Animations & Datatriggers

I have a StackPanel with an animation. The animation looks like this:

 <DataTrigger Binding="{Binding UseCurrentWindowsUser}" Value="True">
                <DataTrigger.EnterActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <Storyboard>
                                <DoubleAnimation From="80" To="0" Duration="00:00:0.5" Storyboard.TargetProperty="Height">
                                    <DoubleAnimation.EasingFunction>
                                        <BounceEase Bounces="3" EasingMode="EaseOut" Bounciness="5" />
                                    </DoubleAnimation.EasingFunction>
                                </DoubleAnimation>
                            </Storyboard>
                        </Storyboard>
                    </BeginStoryboard>
                </DataTrigger.EnterActions>
                <DataTrigger.ExitActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <Storyboard x:Name="myhideStoryboard">
                                <DoubleAnimation BeginTime="0:0:0.1" From="0" To="80" Duration="00:00:0.5" Storyboard.TargetProperty="Height">
                                    <DoubleAnimation.EasingFunction>
                                        <BounceEase Bounces="3" EasingMode="EaseOut" Bounciness="5" />
                                    </DoubleAnimation.EasingFunction>
                                </DoubleAnimation>
                            </Storyboard>
                        </Storyboard>
                    </BeginStoryboard>
                </DataTrigger.ExitActions>
            </DataTrigger>

This animation will change the height of the stackpanel when the property UseCurrentWindowsUser is true. This property is used as a binding to a CheckBox , IsChecked . The problem I face is that this property should by default be set to true, therefore the animation will trigger once the UserControl is loaded. I only want this to happend once the user actually checks or uncheck the CheckBox . Should I use a RoutedEvent insted? Anyone solved an issue like this before?

The property looks like this:

    private bool _useCurrentWindowsUser = true;
    public bool UseCurrentWindowsUser
    {
        get { return _useCurrentWindowsUser; }
        set
        {
            SetProperty(ref _useCurrentWindowsUser, value);
            UserName = value ? WindowsIdentity.GetCurrent()?.Name : string.Empty;
        }
    }

Here is a pure XAML solution which is a little tricky but fairly pretty. The idea is you need another trigger listening to the same property change but the Animation is started after the actual animation you have. This animation will override the other animation in the exact duration but then stop effecting by using FillBehavior = FillBehavior.Stop . The override trigger is also done once (by using BindingMode.OneTime ). So after the first time suppressing the actual trigger from working normally, everything will be normal again (the actual trigger then can work normally):

Append this XAML code AFTER your current DataTrigger so that it will override the animations correctly:

<DataTrigger Binding="{Binding UseCurrentWindowsUser, Mode=OneTime}" Value="True">
            <DataTrigger.EnterActions>
                <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation From="0" To="0" Duration="00:00:0.5" 
                             Storyboard.TargetProperty="Height" FillBehavior="Stop"/>
                        </Storyboard>
                </BeginStoryboard>
            </DataTrigger.EnterActions>
</DataTrigger>

As you can see, the fake animation just keeps the Height unchanged at 0 in the same duration of 0.5 seconds. It makes the effect that when UseCurrentWindowsUser is true initially, the Height is set immediately to 0 instead of being animated from 80 to 0 , which is weird at the initial time.

private bool firstTime = true;
private bool _useCurrentWindowsUser = true;
public bool UseCurrentWindowsUser
{
    get { return _useCurrentWindowsUser; }
    set
    {
        if(!firstTime)
            SetProperty(ref _useCurrentWindowsUser, value);
        firstTime=false;
        UserName = value ? WindowsIdentity.GetCurrent()?.Name : string.Empty;
    }
}

If you have to set that property the first time to, create a new property whith the same value, but without the first time initlialization.

Set default value to null/false in propertymetadata while registering DP. This will make your stackpanel appear with height of 80 initially. Setting it true will collapse your stackpanel on loading.

public class ViewModel : DependencyObject
    {
        public bool  UseCurrentWindowsUser
        {
            get { return (bool )GetValue(UseCurrentWindowsUserProperty); }
            set { SetValue(UseCurrentWindowsUserProperty, value); }
        }

        // Using a DependencyProperty as the backing store for UseCurrentWindowsUser.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty UseCurrentWindowsUserProperty =
            DependencyProperty.Register("UseCurrentWindowsUser", typeof(bool ), typeof(ViewModel), new PropertyMetadata(null));

    }

Set UpdateSourceTrigger to Explicit :

<CheckBox x:Name="MyCB" IsChecked="{Binding UseCurrentWindowsUser, UpdateSourceTrigger=Explicit}" Loaded="MyCB_Loaded" Click="MyCB_Click"/>

Set your CB checked to true in its Loaded event handler, as you want it to true initially.

private void MyCB_Loaded(object sender, RoutedEventArgs e)
        {
            MyCB.IsChecked = true;
        }

Update your source in CB click event handler :

private void MyCB_Click(object sender, RoutedEventArgs e)
    {
        MyCB.GetBindingExpression(CheckBox.IsCheckedProperty).UpdateSource();
    }

Now, your StackPanel will appear with height of 80, your checkbox will be checked. Action starts once you start clicking your checkbox.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM