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 | - | 新規作成 |