Grid を GridSplitter を使って分割レイアウト表示することがあります。
この分割表示をアニメーションで動作する方法を記載します。
Grid.ColumnDefinition をアニメーションするには単純に DoubleAnimation で実現することはできないようです。
ここではインターネットを調査して見つけたプログラムをまねして、AnimationTimeline の派生クラスを使うことで実現しています。
この手法はいろいろと応用できそうなので、こちらのプログラミングアイテムに記録を残すことにしました。
作成するプログラムは下図の通りです。
・画面中央のボタンをクリックすることで、画面レイアウトがアニメーションにより開閉します。
・ボタンの矢印も逆方向を向きます。
[動画] 動作例です
コンパイラ : | Visual Studio 2015 pro. | |
c# | ||
フレームワーク: | .NET Framework 4.0 | |
OS : | Windows10 home | |
["MainWindow.xaml"]
<Window x:Class="test_GridSplitter_02.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:test_GridSplitter_02" mc:Ignorable="d" Title="MainWindow" Height="350" Width="525" ResizeMode="CanResizeWithGrip"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="100*" Name="menuWidth"/> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="100*"/> </Grid.ColumnDefinitions> <StackPanel Margin="0"/> <GridSplitter x:Name="menuGlidSplitter" HorizontalAlignment="Center" Margin="0" Width="5" Grid.Column="1" HorizontalContentAlignment="Center" VerticalContentAlignment="Stretch"/> <StackPanel Grid.Column="2" Margin="0"> <Image Source="P1070769.jpg" VerticalAlignment="Top" Stretch="UniformToFill"/> </StackPanel> <Button x:Name="btnOpenClose" Content="⇐" Margin="0,0,-15,0" Height="24" HorizontalAlignment="Right" Width="24" VerticalContentAlignment="Stretch" FontSize="16" Click="Button_Click"/> </Grid> </Window>
using System; using System.Windows; // GridLength, ContentElement.BeginAnimation using System.Windows.Controls; using System.Windows.Media.Animation; // EasingFunctionBase, CubicEase namespace test_GridSplitter_02 { /// <summary> /// MainWindow.xaml の相互作用ロジック /// </summary> public partial class MainWindow : Window { private bool bMenuOpened = true; private GridLength menuWidthOrg; private EasingFunctionBase ease = new CubicEase(); private GridLength fromMenuWidth; private GridLength toMenuWidth; public MainWindow() { InitializeComponent(); } private void Button_Click(object sender, RoutedEventArgs e) { var glaMenu = new GridLengthAnimation(); if ( bMenuOpened == true) { // menu を閉じる bMenuOpened = false; // GridSplitter の可動範囲を指定する //menuWidth.MinWidth = 0; menuWidth.MaxWidth = 500; menuWidthOrg = menuWidth.Width; fromMenuWidth = menuWidth.Width; toMenuWidth = new GridLength(0.0, GridUnitType.Star); // EasingFunction definitions. ease.EasingMode = EasingMode.EaseInOut; glaMenu.EasingFunction = ease; } else { // menu を開く bMenuOpened = true; // GridSplitter の可動範囲を指定する //menuWidth.MinWidth = 0; menuWidth.MaxWidth = 500; //fromMenuWidth = new GridLength(menuWidth.ActualWidth); fromMenuWidth = menuWidth.Width; toMenuWidth = menuWidthOrg; // EasingFunction definitions. ease.EasingMode = EasingMode.EaseInOut; glaMenu.EasingFunction = ease; } // GridLengthAnimation を設定 glaMenu.Completed += GlaMenu_Completed; // アニメーション完了を通知 glaMenu.Duration = new Duration(TimeSpan.FromSeconds(0.5)); // 0.5秒 でアニメーション //glaMenu.FillBehavior = FillBehavior.HoldEnd; // FillBehavior の設定は重要。どちらを使う? glaMenu.FillBehavior = FillBehavior.Stop; // FillBehavior の設定は重要。どちらを使う? glaMenu.From = fromMenuWidth; glaMenu.To = toMenuWidth; // アニメーション開始 menuWidth.BeginAnimation(ColumnDefinition.WidthProperty, glaMenu); } private void GlaMenu_Completed(object sender, EventArgs e) { menuWidth.Width = toMenuWidth; if ( bMenuOpened) { btnOpenClose.Content = "⇐"; menuGlidSplitter.IsEnabled = true; } else { btnOpenClose.Content = "⇒"; menuGlidSplitter.IsEnabled = false; } } } }
using System; using System.Windows; using System.Windows.Media.Animation; /// <summary> /// 下記URLの記事に記載のコードを参考にしました。 /// http://stackoverflow.com/questions/9358025/gridsplitter-not-working-after-applying-an-animation-to-a-grid-column /// </summary> namespace test_GridSplitter_02 { internal class GridLengthAnimation : AnimationTimeline { public static readonly DependencyProperty FromProperty; public static readonly DependencyProperty ToProperty; public static readonly DependencyProperty EasingFunctionProperty; static GridLengthAnimation() { FromProperty = DependencyProperty.Register("From", typeof(GridLength), typeof(GridLengthAnimation)); ToProperty = DependencyProperty.Register("To", typeof(GridLength), typeof(GridLengthAnimation)); EasingFunctionProperty = DependencyProperty.Register("EasingFunction", typeof(IEasingFunction), typeof(GridLengthAnimation)); } protected override Freezable CreateInstanceCore() { return new GridLengthAnimation(); } public override Type TargetPropertyType { get { return typeof(GridLength); } } public IEasingFunction EasingFunction { get { return (IEasingFunction)GetValue(GridLengthAnimation.EasingFunctionProperty); } set { SetValue(GridLengthAnimation.EasingFunctionProperty, value); } } public GridLength From { get { return (GridLength)GetValue(GridLengthAnimation.FromProperty); } set { SetValue(GridLengthAnimation.FromProperty, value); } } public GridLength To { get { return (GridLength)GetValue(GridLengthAnimation.ToProperty); } set { SetValue(GridLengthAnimation.ToProperty, value); } } public override object GetCurrentValue(object defaultOriginValue, object defaultDestinationValue, AnimationClock animationClock) { double fromValue = ((GridLength)GetValue(GridLengthAnimation.FromProperty)).Value; double toValue = ((GridLength)GetValue(GridLengthAnimation.ToProperty)).Value; IEasingFunction easingFunction = this.EasingFunction; double progress = (easingFunction != null) ? easingFunction.Ease(animationClock.CurrentProgress.Value) : animationClock.CurrentProgress.Value; if (fromValue > toValue) { return new GridLength((1 - progress) * (fromValue - toValue) + toValue, this.To.IsStar ? GridUnitType.Star : GridUnitType.Pixel); } else { return new GridLength((progress) * (toValue - fromValue) + fromValue, this.To.IsStar ? GridUnitType.Star : GridUnitType.Pixel); } } } }
サンプルプログラム ダウンロード
本ページの情報は、特記無い限り下記 MIT ライセンスで提供されます。
2022-12-10 | - | ページデザイン更新 |
2017-08-15 | - | 新規作成 |