SourceTree for Windows で使われているWPFライブラリ
Free Mercurial and Git Client for Windows and Mac | Atlassian SourceTreeをダウンロードしてみたら、全然知らないWPFライブラリが使われてるので、備忘録を兼ねてメモ。
- WPF Converters - Home コンバーター
- ScrollableTabPanel スクロール、クローズ可能なタブコントロール
- Circular Progress Bar 円形プログレスバー
- WPF Task Dialog Wrapper タスクダイアログ?
- CommandSink コマンド
- ListViewLayoutManager ListView/GridView のカラムレイアウト
- dg9ngf/MultiSelectTreeView TreeView で複数選択
- Drag/Drop component ドラッグ&ドロップ
- RestSharp RESTクライアント
System.Windows.Forms.Button.PerformClickのWPF版
(new ButtonAutomationPeer(button).GetPattern(PatternInterface.Invoke) as IInvokeProvider).Invoke();
EnumをComboBoxに表示する。
アセンブリHogeAsmに含まれるEnum、HogeEnumをComboBoxに表示。
<UserControl x:Class="Hoge.HogeView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:System="clr-namespace:System;assembly=mscorlib" xmlns:hoge="clr-namespace:Hoge;assembly=HogeAsm"> <UserControl.Resources> <ObjectDataProvider x:Key="EnumList" MethodName="GetValues" ObjectType="{x:Type System:Enum}"> <ObjectDataProvider.MethodParameters> <x:Type TypeName="hoge:HogeEnum"/> </ObjectDataProvider.MethodParameters> </ObjectDataProvider> </UserControl.Resources> <Grid> <ComboBox ItemsSource="{Binding Source={StaticResource EnumList}}" /> </Grid> </UserControl>
WPFでコントロールをアニメーションさせてみる
Expression Blend を使えばアニメーションは簡単にできるんだけど、アニメーション中は Width プロパティとかに Auto を指定できないので微妙にめんどくさい(ちなみにコードだと Auto は Double.NaN で指定できる)。
なので、細かい操作は Visual Studio を使ってコードを書いた方が楽みたい。
そんなわけで、以下アニメーションの覚え書き。
1つのコントロールの1つのプロパティをアニメーション
- System.Windows.Media.Animation.DoubleAnimation クラスみたいな Animation クラスを生成する。コンストラクタで開始値・目標値・アニメーション時間を指定しておく。 Animation クラスは、変化させる型に応じたものを選択すること。特殊なのは Enum で、 ObjectAnimationUsingKeyFrames クラスを使用する。
- 変化させるコントロールの System.Windows.Media.Animation.Animatable#BeginAnimation メソッドでアニメーションを開始する。引数は、変化させるプロパティを表す依存プロパティと、上で生成した Animation クラス。
1つのコントロールの2つ以上のプロパティをアニメーション
アプローチとしては2つ。
- Animation クラスを複数用意して、BeginAnimation を必要なだけ呼ぶ。
- System.Windows.Media.Animation.StoryBoard クラスを使う。
MS的には後者が推奨なようですな。具体的な方法はこんな感じ。
- Animation クラスを作成。
- StoryBoard#SetTargetProperty で、上記で生成した Animation クラスと、変化させるプロパティを表す依存プロパティを指定する。Animatable#BeginAnimation とは引数の順番が入れ替わっていて、依存プロパティを指定するのも PropertyPath 経由になっていてわかりにくい・・・。なんで依存プロパティじゃ駄目なんだろう?
- 変化させるすべてのプロパティに対応する Animation クラスを生成する。
- StoryBoard クラスを生成して、Children プロパティに生成した Animation クラスを追加する。
- 変化させるコントロールの Animatable#BeginStoryboard メソッドでアニメーションを開始する。引数は上記で生成した StoryBoard クラス。
2つ以上のコントロールをアニメーション
これがサンプルが見つからなくて、かなりはまった。方法としては、1つのコントロールの2つ以上のプロパティをアニメーションとほとんど同じ。違いは StoryBoard#SetTargetName で、変化させるコントロールを指定するところ。オブジェクトを指定するんじゃなくて、文字列で名前を指定するのが嫌な感じ。
- Animation クラスを作成。
- StoryBoard#SetTargetProperty で、上記で生成した Animation クラスと、変化させるプロパティを表す依存プロパティを指定する。
- StoryBoard#SetTargetName で、上記で生成した Animation クラスと、変化させるコントロール名を指定する。
- 変化させるすべてのコントロール・プロパティに対応する Animation クラスを生成する。
- StoryBoard クラスを生成して、Children プロパティに生成した Animation クラスを追加する。
- Animatable#BeginStoryboard メソッドでアニメーションを開始する。引数は上記で生成した StoryBoard クラス。メソッドを呼ぶインスタンスは何でもいいみたい。
サンプルコード
WindowにCanvasを置いて、その上にボタンを3つ(left 、 center 、 right)を置いた場合。
using System; using System.IO; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Navigation; namespace SampleWPF { public partial class Window1 { public Window1() { this.InitializeComponent(); } private void left_Click(object sender, RoutedEventArgs e) { //1つのコントロールの1つのプロパティをアニメーション Duration d = new Duration(TimeSpan.FromMilliseconds(100)); DoubleAnimation a = new DoubleAnimation(300, d); left.BeginAnimation(Canvas.WidthProperty, a); } private void center_Click(object sender, RoutedEventArgs e) { //1つのコントロールの2つ以上のプロパティをアニメーション Storyboard s = new Storyboard(); Duration d = new Duration(TimeSpan.FromMilliseconds(100)); DoubleAnimation a1 = new DoubleAnimation(50, d); Storyboard.SetTargetProperty(a1, new PropertyPath(Canvas.WidthProperty)); s.Children.Add(a1); DoubleAnimation b1 = new DoubleAnimation(50, d); Storyboard.SetTargetProperty(b1, new PropertyPath(Canvas.HeightProperty)); s.Children.Add(b1); center.BeginStoryboard(s); } private void right_Click(object sender, RoutedEventArgs e) { //2つ以上のコントロールをアニメーション Storyboard s = new Storyboard(); Duration d = new Duration(TimeSpan.FromMilliseconds(100)); DoubleAnimation a1 = new DoubleAnimation(100, d); Storyboard.SetTargetProperty(a1, new PropertyPath(Canvas.WidthProperty)); Storyboard.SetTargetName(a1, "left"); s.Children.Add(a1); DoubleAnimation b1 = new DoubleAnimation(100, d); Storyboard.SetTargetProperty(b1, new PropertyPath(Canvas.HeightProperty)); Storyboard.SetTargetName(b1, "left"); s.Children.Add(b1); DoubleAnimation a2 = new DoubleAnimation(500, d); Storyboard.SetTargetProperty(a2, new PropertyPath(Canvas.WidthProperty)); Storyboard.SetTargetName(a2, "right"); s.Children.Add(a2); DoubleAnimation b2 = new DoubleAnimation(500, d); Storyboard.SetTargetProperty(b2, new PropertyPath(Canvas.HeightProperty)); Storyboard.SetTargetName(b2, "right"); s.Children.Add(b2); this.BeginStoryboard(s); } } }