teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

1

見直しキャンペーン中

2023/07/29 09:54

投稿

TN8001
TN8001

スコア10114

answer CHANGED
@@ -1,142 +1,146 @@
1
- > ソースコード中に、手計算で算出した数値がいくつかありますが、それらは自動的に算出させて、手計算を不要にしたいです。
2
-
3
- よくあるのは`DoubleAnimation`は、0~1の比率としてアニメーションさせる手法です(そのかわり`Converter`が必要になります)
4
- [WPF animation: binding to the "To" attribute of storyboard animation - Stack Overflow](https://stackoverflow.com/questions/2186933/wpf-animation-binding-to-the-to-attribute-of-storyboard-animation/14164245#14164245)
5
-
6
- 比率でやったとしても基準になる数値は必要になりますが、お手軽なのはダミーで実際に作ってしまうことです(`Collapsed`にしてしまうとサイズ0になってしまうので、`Hidden`にしたり何かの裏に隠します^^;
7
-
8
- ```xaml
9
- <Window
10
- x:Class="Questions371156.MainWindow"
11
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
12
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
13
- xmlns:local="clr-namespace:Questions371156"
14
- Width="800"
15
- Height="450">
16
- <Window.Resources>
17
- <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
18
- <local:MultiplyConverter x:Key="multiplyConverter" />
19
- </Window.Resources>
20
- <DockPanel>
21
- <StackPanel Background="DarkGray">
22
- <StackPanel.Width>
23
- <!-- 比率が0~1にアニメーションすると、StackPanel.Widthが53~145に変化する(ようなコンバータを書く) -->
24
- <MultiBinding Converter="{StaticResource multiplyConverter}">
25
- <!-- 初期値: 53の部分 -->
26
- <Binding ElementName="dummy_min_button" Path="ActualWidth" />
27
- <!-- ターゲット値: 145の部分 -->
28
- <Binding ElementName="side_menu_panel2" Path="DesiredSize.Width" />
29
- <!-- 比率: 0~1で変化する -->
30
- <Binding ElementName="dummy_width_ratio" Path="Width" />
31
- </MultiBinding>
32
- </StackPanel.Width>
33
-
34
- <StackPanel.Triggers>
35
- <EventTrigger RoutedEvent="MouseEnter" SourceName="side_menu_panel2">
36
- <BeginStoryboard>
37
- <Storyboard>
38
- <DoubleAnimation
39
- Storyboard.TargetName="dummy_width_ratio"
40
- Storyboard.TargetProperty="Width"
41
- To="1"
42
- Duration="0:0:0.3">
43
- <DoubleAnimation.EasingFunction>
44
- <CubicEase />
45
- </DoubleAnimation.EasingFunction>
46
- </DoubleAnimation>
47
- </Storyboard>
48
- </BeginStoryboard>
49
- </EventTrigger>
50
- <EventTrigger RoutedEvent="MouseLeave" SourceName="side_menu_panel2">
51
- <BeginStoryboard>
52
- <Storyboard>
53
- <DoubleAnimation
54
- Storyboard.TargetName="dummy_width_ratio"
55
- Storyboard.TargetProperty="Width"
56
- To="0"
57
- Duration="0:0:0.15">
58
- <DoubleAnimation.EasingFunction>
59
- <CubicEase />
60
- </DoubleAnimation.EasingFunction>
61
- </DoubleAnimation>
62
- </Storyboard>
63
- </BeginStoryboard>
64
- </EventTrigger>
65
- </StackPanel.Triggers>
66
- <StackPanel.Resources>
67
- <Style TargetType="RadioButton">
68
- <Setter Property="Padding" Value="4" />
69
- <Setter Property="VerticalContentAlignment" Value="Center" />
70
- <Setter Property="Template">
71
- <Setter.Value>
72
- <ControlTemplate TargetType="RadioButton">
73
- <Border Padding="{TemplateBinding Padding}" Cursor="Hand">
74
- <BulletDecorator>
75
- <BulletDecorator.Bullet>
76
- <!-- Background使ってなさそうなのでこっちで使いました^^; -->
77
- <Ellipse
78
- Width="45"
79
- Height="45"
80
- Fill="{TemplateBinding Background}" />
81
- </BulletDecorator.Bullet>
82
- <ContentPresenter
83
- x:Name="contentPresenter"
84
- Margin="20,0,0,0"
85
- VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
86
- Visibility="{TemplateBinding HasContent, Converter={StaticResource BooleanToVisibilityConverter}}" />
87
- </BulletDecorator>
88
- </Border>
89
- </ControlTemplate>
90
- </Setter.Value>
91
- </Setter>
92
- </Style>
93
- </StackPanel.Resources>
94
- <!-- ダミーを隠すためにGridで重なってもらう -->
95
- <Grid>
96
- <!-- 閉じたときのサイズ計算用ダミー -->
97
- <RadioButton x:Name="dummy_min_button" HorizontalAlignment="Left" />
98
- <!-- 比率計算用ダミー -->
99
- <Border x:Name="dummy_width_ratio" Width="0" />
100
-
101
- <StackPanel x:Name="side_menu_panel2">
102
- <RadioButton Background="#FF21E402" Content="メニュー1" />
103
- <RadioButton Background="MediumVioletRed" Content="メニューーー2" />
104
- </StackPanel>
105
- </Grid>
106
- </StackPanel>
107
- <Rectangle Fill="Gray" />
108
- </DockPanel>
109
- </Window>
110
- ```
111
-
112
- ```C#
113
- using System;
114
- using System.Globalization;
115
- using System.Windows;
116
- using System.Windows.Data;
117
-
118
- namespace Questions371156
119
- {
120
- public class MultiplyConverter : IMultiValueConverter
121
- {
122
- // values[0]:初期値 values[1]:ターゲット値 values[2]:比率 が入力される前提
123
- public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
124
- => (double)values[0] + (double)values[2] * ((double)values[1] - (double)values[0]);
125
-
126
- public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) => throw new NotImplementedException();
127
- }
128
-
129
- public partial class MainWindow : Window
130
- {
131
- public MainWindow() => InitializeComponent();
132
- }
133
- }
134
- ```
135
-
136
- ---
137
-
138
-
139
- アニメーションは「引っ込むときは速くする・イージングをつける」と、オサレな感じになると思います^^
140
-
141
- WPF用ではありませんがUXのガイドラインがあります。
1
+ > ソースコード中に、手計算で算出した数値がいくつかありますが、それらは自動的に算出させて、手計算を不要にしたいです。
2
+
3
+ よくあるのは`DoubleAnimation`は、0~1の比率としてアニメーションさせる手法です(そのかわり`Converter`が必要になります)
4
+ [WPF animation: binding to the "To" attribute of storyboard animation - Stack Overflow](https://stackoverflow.com/questions/2186933/wpf-animation-binding-to-the-to-attribute-of-storyboard-animation/14164245#14164245)
5
+
6
+ 比率でやったとしても基準になる数値は必要になりますが、お手軽なのはダミーで実際に作ってしまうことです(`Collapsed`にしてしまうとサイズ0になってしまうので、`Hidden`にしたり何かの裏に隠します^^;
7
+
8
+ ```xml
9
+ <Window
10
+ x:Class="Questions371156.MainWindow"
11
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
12
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
13
+ xmlns:local="clr-namespace:Questions371156"
14
+ Width="800"
15
+ Height="450">
16
+ <Window.Resources>
17
+ <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
18
+ <local:MultiplyConverter x:Key="multiplyConverter" />
19
+ </Window.Resources>
20
+ <DockPanel>
21
+ <StackPanel Background="DarkGray">
22
+ <StackPanel.Width>
23
+ <!-- 比率が0~1にアニメーションすると、StackPanel.Widthが53~145に変化する(ようなコンバータを書く) -->
24
+ <MultiBinding Converter="{StaticResource multiplyConverter}">
25
+ <!-- 初期値: 53の部分 -->
26
+ <Binding ElementName="dummy_min_button" Path="ActualWidth" />
27
+ <!-- ターゲット値: 145の部分 -->
28
+ <Binding ElementName="side_menu_panel2" Path="DesiredSize.Width" />
29
+ <!-- 比率: 0~1で変化する -->
30
+ <Binding ElementName="dummy_width_ratio" Path="Width" />
31
+ </MultiBinding>
32
+ </StackPanel.Width>
33
+
34
+ <StackPanel.Triggers>
35
+ <EventTrigger RoutedEvent="MouseEnter" SourceName="side_menu_panel2">
36
+ <BeginStoryboard>
37
+ <Storyboard>
38
+ <DoubleAnimation
39
+ Storyboard.TargetName="dummy_width_ratio"
40
+ Storyboard.TargetProperty="Width"
41
+ To="1"
42
+ Duration="0:0:0.3">
43
+ <DoubleAnimation.EasingFunction>
44
+ <CubicEase />
45
+ </DoubleAnimation.EasingFunction>
46
+ </DoubleAnimation>
47
+ </Storyboard>
48
+ </BeginStoryboard>
49
+ </EventTrigger>
50
+ <EventTrigger RoutedEvent="MouseLeave" SourceName="side_menu_panel2">
51
+ <BeginStoryboard>
52
+ <Storyboard>
53
+ <DoubleAnimation
54
+ Storyboard.TargetName="dummy_width_ratio"
55
+ Storyboard.TargetProperty="Width"
56
+ To="0"
57
+ Duration="0:0:0.15">
58
+ <DoubleAnimation.EasingFunction>
59
+ <CubicEase />
60
+ </DoubleAnimation.EasingFunction>
61
+ </DoubleAnimation>
62
+ </Storyboard>
63
+ </BeginStoryboard>
64
+ </EventTrigger>
65
+ </StackPanel.Triggers>
66
+ <StackPanel.Resources>
67
+ <Style TargetType="RadioButton">
68
+ <Setter Property="Padding" Value="4" />
69
+ <Setter Property="VerticalContentAlignment" Value="Center" />
70
+ <Setter Property="Template">
71
+ <Setter.Value>
72
+ <ControlTemplate TargetType="RadioButton">
73
+ <Border
74
+ Padding="{TemplateBinding Padding}"
75
+ Background="Transparent"
76
+ Cursor="Hand">
77
+ <BulletDecorator>
78
+ <BulletDecorator.Bullet>
79
+ <!-- Background使ってなさそうなのでこっちで使いました^^; -->
80
+ <Ellipse
81
+ Width="45"
82
+ Height="45"
83
+ Fill="{TemplateBinding Background}" />
84
+ </BulletDecorator.Bullet>
85
+ <ContentPresenter
86
+ x:Name="contentPresenter"
87
+ Margin="20,0,0,0"
88
+ VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
89
+ Visibility="{TemplateBinding HasContent, Converter={StaticResource BooleanToVisibilityConverter}}" />
90
+ </BulletDecorator>
91
+ </Border>
92
+ </ControlTemplate>
93
+ </Setter.Value>
94
+ </Setter>
95
+ </Style>
96
+ </StackPanel.Resources>
97
+ <!-- ダミーを隠すためにGridで重なってもらう -->
98
+ <Grid>
99
+ <!-- 閉じたときのサイズ計算用ダミー -->
100
+ <RadioButton x:Name="dummy_min_button" HorizontalAlignment="Left" />
101
+ <!-- 比率計算用ダミー -->
102
+ <Border x:Name="dummy_width_ratio" Width="0" />
103
+
104
+ <StackPanel x:Name="side_menu_panel2">
105
+ <RadioButton Background="#FF21E402" Content="メニュー1" />
106
+ <RadioButton Background="MediumVioletRed" Content="メニューーー2" />
107
+ </StackPanel>
108
+ </Grid>
109
+ </StackPanel>
110
+ <Rectangle Fill="Gray" />
111
+ </DockPanel>
112
+ </Window>
113
+ ```
114
+
115
+ ```cs
116
+ using System;
117
+ using System.Globalization;
118
+ using System.Windows;
119
+ using System.Windows.Data;
120
+
121
+ namespace Questions371156
122
+ {
123
+ public class MultiplyConverter : IMultiValueConverter
124
+ {
125
+ // values[0]:初期値 values[1]:ターゲット値 values[2]:比率 が入力される前提
126
+ public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
127
+ => (double)values[0] + (double)values[2] * ((double)values[1] - (double)values[0]);
128
+
129
+ public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) => throw new NotImplementedException();
130
+ }
131
+
132
+ public partial class MainWindow : Window
133
+ {
134
+ public MainWindow() => InitializeComponent();
135
+ }
136
+ }
137
+ ```
138
+ ![アプリ動画](https://ddjkaamml8q8x.cloudfront.net/questions/2023-07-29/f2ba8ea8-e660-47e4-9cc5-c7ffc2f8fd8f.gif)
139
+
140
+ ---
141
+
142
+
143
+ アニメーションは「引っ込むときは速くする・イージングをつける」と、オサレな感じになると思います^^
144
+
145
+ WPF用ではありませんがUXのガイドラインがあります。
142
146
  [モーション (Windows アプリでのアニメーション) - Windows apps | Microsoft Docs](https://docs.microsoft.com/ja-jp/windows/apps/design/motion/motion-in-practice)