Search code examples
wpfsplit-button

WPF: how to implement a button that make 2 other buttons visible with fading


I want to Implement special button and i don't know even how to start with this.

I want my Button's content property to be: Play. When clicking on it, I want 2 other Buttons to pop up in the left and in the right sides: Single Play and Parallel Play


Solution

  • After a lot of discussion, here is the result to solve this problem:

    xaml:

    <Window x:Class="WpfApplication3.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:my="clr-namespace:WpfApplication3"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <StackPanel Orientation="Horizontal">
            <Button Name="btnSinglePlay" Visibility="Collapsed" my:VisibilityAnimation.IsActive="True">SinglePlay</Button>
            <Button Name="btnPlay" Click="btnPlay_Click">Play</Button>
            <Button Name="btnParallelPlay" Visibility="Collapsed" my:VisibilityAnimation.IsActive="True">ParallelPlay</Button>
        </StackPanel>
    </Grid>
    

    C# to set the 2 sides button visible.

    private void btnPlay_Click(object sender, RoutedEventArgs e)
            {
                btnSinglePlay.Visibility = Visibility.Visible;
                btnParallelPlay.Visibility = Visibility.Visible;
            }
    

    And the c# code to permit the fade in/fade out. It comes from WPF Fade Animation so props to Anvaka, not to me.

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Media.Animation;
    
    namespace WpfApplication3
    {
        public class VisibilityAnimation : DependencyObject
        {
            private const int DURATION_MS = 200;
    
            private static readonly Hashtable _hookedElements = new Hashtable();
    
            public static readonly DependencyProperty IsActiveProperty =
              DependencyProperty.RegisterAttached("IsActive",
              typeof(bool),
              typeof(VisibilityAnimation),
              new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnIsActivePropertyChanged)));
    
            public static bool GetIsActive(UIElement element)
            {
                if (element == null)
                {
                    throw new ArgumentNullException("element");
                }
    
                return (bool)element.GetValue(IsActiveProperty);
            }
    
            public static void SetIsActive(UIElement element, bool value)
            {
                if (element == null)
                {
                    throw new ArgumentNullException("element");
                }
                element.SetValue(IsActiveProperty, value);
            }
    
            static VisibilityAnimation()
            {
                UIElement.VisibilityProperty.AddOwner(typeof(FrameworkElement),
                                                      new FrameworkPropertyMetadata(Visibility.Visible, new PropertyChangedCallback(VisibilityChanged), CoerceVisibility));
            }
    
            private static void VisibilityChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                // So what? Ignore.
            }
    
            private static void OnIsActivePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                var fe = d as FrameworkElement;
                if (fe == null)
                {
                    return;
                }
                if (GetIsActive(fe))
                {
                    HookVisibilityChanges(fe);
                }
                else
                {
                    UnHookVisibilityChanges(fe);
                }
            }
    
            private static void UnHookVisibilityChanges(FrameworkElement fe)
            {
                if (_hookedElements.Contains(fe))
                {
                    _hookedElements.Remove(fe);
                }
            }
    
            private static void HookVisibilityChanges(FrameworkElement fe)
            {
                _hookedElements.Add(fe, false);
            }
    
            private static object CoerceVisibility(DependencyObject d, object baseValue)
            {
                var fe = d as FrameworkElement;
                if (fe == null)
                {
                    return baseValue;
                }
    
                if (CheckAndUpdateAnimationStartedFlag(fe))
                {
                    return baseValue;
                }
                // If we get here, it means we have to start fade in or fade out
                // animation. In any case return value of this method will be
                // Visibility.Visible. 
    
                var visibility = (Visibility)baseValue;
    
                var da = new DoubleAnimation
                {
                    Duration = new Duration(TimeSpan.FromMilliseconds(DURATION_MS))
                };
    
                da.Completed += (o, e) =>
                {
                    // This will trigger value coercion again
                    // but CheckAndUpdateAnimationStartedFlag() function will reture true
                    // this time, and animation will not be triggered.
                    fe.Visibility = visibility;
                    // NB: Small problem here. This may and probably will brake 
                    // binding to visibility property.
                };
    
                if (visibility == Visibility.Collapsed || visibility == Visibility.Hidden)
                {
                    da.From = 1.0;
                    da.To = 0.0;
                }
                else
                {
                    da.From = 0.0;
                    da.To = 1.0;
                }
    
                fe.BeginAnimation(UIElement.OpacityProperty, da);
                return Visibility.Visible;
            }
    
            private static bool CheckAndUpdateAnimationStartedFlag(FrameworkElement fe)
            {
                var hookedElement = _hookedElements.Contains(fe);
                if (!hookedElement)
                {
                    return true; // don't need to animate unhooked elements.
                }
    
                var animationStarted = (bool)_hookedElements[fe];
                _hookedElements[fe] = !animationStarted;
    
                return animationStarted;
            }
        }
    }