zourimusi's blog

作業メモとnanoblock関連

コンテナの型を指定したItemsControl継承クラス

StyleTypedPropertyAttributeとGetContainerForItemOverrideを実装すれば、とりあえずコンテナの型を指定したItemsControl継承クラスが作れるようです。

// StyleTypedPropertyAttributeを指定する
[StyleTypedPropertyAttribute(Property = "ItemContainerStyle", StyleTargetType = typeof(AnimationCanvasItem))]
public class AnimationCanvas : ItemsControl
{
    // ItemContainerとなるオブジェクトを生成して返す
    protected override DependencyObject GetContainerForItemOverride()
    {
        return new AnimationCanvasItem();
    }
}

なお、コンテナのクラスとXamlは以下のようなものを作りました。

public class AnimationCanvasItem : ContentControl
{
    // 目標とするCanvas.Xの依存関係プロパティ
    public static readonly DependencyProperty XProperty = DependencyProperty.Register("X", typeof(double), typeof(AnimationCanvasItem), new PropertyMetadata( (sender, e) =>
    {
        DoubleAnimation animation = new DoubleAnimation( (double)e.OldValue, (double)e.NewValue, new Duration(TimeSpan.FromMilliseconds(100)));
        Storyboard.SetTarget(animation, (DependencyObject)sender);
        Storyboard.SetTargetProperty(animation, new PropertyPath("(Canvas.Left)"));

        var story = new Storyboard();
        story.Children.Add(animation);
        story.Begin();
    }));

    // 目標とするCanvas.Yの依存関係プロパティ
    public static readonly DependencyProperty YProperty = DependencyProperty.Register("Y", typeof(double), typeof(AnimationCanvasItem), new PropertyMetadata( (sender, e) =>
    {
        DoubleAnimation animation = new DoubleAnimation( (double)e.OldValue, (double)e.NewValue, new Duration(TimeSpan.FromMilliseconds(100)));
        Storyboard.SetTarget(animation, (DependencyObject)sender);
        Storyboard.SetTargetProperty(animation, new PropertyPath("(Canvas.Top)"));

        var story = new Storyboard();
        story.Children.Add(animation);
        story.Begin();
    }));

    // 目標とするCanvas.Xを取得または設定します
    public double X
    {
        get { return (double)this.GetValue(AnimationCanvasItem.XProperty); }
        set { this.SetValue(AnimationCanvasItem.XProperty, value); }
    }

    // 目標とするCanvas.Yを取得または設定します
    public double Y
    {
        get { return (double)this.GetValue(AnimationCanvasItem.YProperty); }
        set { this.SetValue(AnimationCanvasItem.YProperty, value); }
    }
}
<contorls:AnimationCanvas ItemsSource="{Binding Items}">
    <contorls:AnimationCanvas.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas/>
        </ItemsPanelTemplate>
    </contorls:AnimationCanvas.ItemsPanel>
    <contorls:AnimationCanvas.ItemContainerStyle>
        <Style TargetType="contorls:AnimationCanvasItem">
            <Setter Property="X" Value="{Binding X, Converter={StaticResource ParameterTimesConverter}, ConverterParameter=32}"/>
            <Setter Property="Y" Value="{Binding Y, Converter={StaticResource ParameterTimesConverter}, ConverterParameter=32}"/>
            <Setter Property="Content">
                <Setter.Value>
                    <Image Source="{Binding Image}" Stretch="None"/>
                </Setter.Value>
            </Setter>
        </Style>
    </contorls:AnimationCanvas.ItemContainerStyle>
</contorls:AnimationCanvas>

Canvas内の複数のコントロールを、移動するたびにアニメーションさせます。Microsoft Excel 2013 がいちいちアニメーションするようになっていたので、NanoBlockMakerでもやってみようと思ったのですが、鬱陶しいので見送りました。

アニメーションのCompletedをコマンド経由で通知したり、DurationやEasingFunctionをバインドできるようにすれば、ゲームなどを作るときに役に立つかもしれません。