x:NameもしくはFindNameの怪 その1

ストーリーボードでスケールを伸ばした後に、コードで戻そうとしたときにへんな挙動が・・・。

Rectangle を伸ばす Storyboardを書こう!

まずは Rectangle を置きます。で、それのスケールを Storyboard で伸ばします。
こんな感じ。

<Storyboard x:Name="Storyboard1">
  <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="rectangle" 
    Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
    <SplineDoubleKeyFrame KeyTime="00:00:00.5000000" Value="20"/>
  </DoubleAnimationUsingKeyFrames>
</Storyboard>

・・・・・・

<Rectangle Width="15" Fill="#FFFF0000" x:Name="rectangle">
  <Rectangle.RenderTransform>
    <TransformGroup>
      <ScaleTransform/>
      <SkewTransform/>
      <RotateTransform/>
      <TranslateTransform/>
    </TransformGroup>
  </Rectangle.RenderTransform>
</Rectangle>

作ったストーリーボードを動かすボタンも置きます。で、そのクリックイベントでストーリーボードを起動します。

<Button Content="伸ばす" Click="Button_Click"/>
private void Button_Click(object sender, RoutedEventArgs e)
{
  Storyboard1.Begin();
}

で、実行してボタンをクリックすると無事にストーリーボードが動いて、幅が伸びるわけです。

幅を元に戻してみよう!

次に、幅を元に戻します。これはストーリーボードではなくコードで直接プロパティに値を設定します。戻す用のボタンをもう一つ追加して、クリックイベントの中で、プロパティを設定します。

<Button Content="戻す" Click="Button_Click_1" />
private void Button_Click_1(object sender, RoutedEventArgs e)
{
  ((rectangle.RenderTransform as TransformGroup).Children[0] as ScaleTransform).ScaleX = 1d;
}

いろんなことを無視しまくっているコードはご愛敬ってことで。

戻りました?戻りましたよね。

ScaleTransformに名前を付けてみよう!

スケールを元に戻すコードが長くってめんどくさいので ScaleTransformに名前を付けてそれを使うようにします。

<Rectangle Width="15" Fill="#FFFF0000" x:Name="rectangle">
  <Rectangle.RenderTransform>
    <TransformGroup>
      <ScaleTransform x:Name="scale"/>
      <SkewTransform/>
      <RotateTransform/>
      <TranslateTransform/>
    </TransformGroup>
  </Rectangle.RenderTransform>
</Rectangle>
private void Button_Click_1(object sender, RoutedEventArgs e)
{
  scale.ScaleX = 1d;
  //((rectangle.RenderTransform as TransformGroup).Children[0] as ScaleTransform).ScaleX = 1d;
}

実行してみてください。戻りました?戻りました?戻らないですよね?

そうです。謎なんです。戻らないんです。

Storyboardのターゲット指定を変えてみよう!

戻らないのでかなり謎なのですが仕方ないので、Storyboardのターゲット指定を変えてみます。

<Storyboard x:Name="Storyboard1">
  <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="scale" 
    Storyboard.TargetProperty="ScaleX">
    <SplineDoubleKeyFrame KeyTime="00:00:00.5000000" Value="20"/>
  </DoubleAnimationUsingKeyFrames>
</Storyboard>

実行してみてください。戻りました?戻りました?戻りましたよね?

そうです。謎なんです。戻ってしまうんです。


そんなこんなで、これに今日2時間近くはまっちまいました。


悔しいのでもうちょっと調べてみます。

インスタンスが同じか見てみよう!!

まぁ、間違いなく同じだとは思うのですが、、、

private void Button_Click_1(object sender, RoutedEventArgs e)
{
  MessageBox.Show(scale.Equals((rectangle.RenderTransform as TransformGroup).Children[0] as ScaleTransform).ToString());
  //scale.ScaleX = 1d;
  //((rectangle.RenderTransform as TransformGroup).Children[0] as ScaleTransform).ScaleX = 1d;

手抜きなのはご愛敬ってことで。

で、やっぱり "true" って表示されます。そりゃそうか。

依存関係プロパティで設定してみよう!!

ストーリボードのXAMLは最初のものに戻しておいてください。

<Storyboard x:Name="Storyboard1">
  <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="rectangle" 
    Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
    <SplineDoubleKeyFrame KeyTime="00:00:00.5000000" Value="20"/>
  </DoubleAnimationUsingKeyFrames>
</Storyboard>

戻すコード側を依存関係プロパティで設定するようにしてみましょう。

private void Button_Click_1(object sender, RoutedEventArgs e)
{
  scale.SetValue(ScaleTransform.ScaleXProperty,1d);
  //scale.ScaleX = 1d;
  //((rectangle.RenderTransform as TransformGroup).Children[0] as ScaleTransform).ScaleX = 1d;
}

やっぱり動きません・・・。

RenderTransformにScaleTransformを直接設定してみよう!!

BlendでRenderTransform系を設定するとTransformGroupが作られるのですが、RenderTransformに直接ScaleTransformを指定してみます。

<Rectangle Fill="#FFFF0000" x:Name="rectangle">
  <Rectangle.RenderTransform>
    <ScaleTransform x:Name="scale"/>
  </Rectangle.RenderTransform>
</Rectangle>

ストーリーボードは下。

<Storyboard x:Name="Storyboard1">
  <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="rectangle" 
    Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)">
    <SplineDoubleKeyFrame KeyTime="00:00:00.5000000" Value="20"/>
  </DoubleAnimationUsingKeyFrames>
</Storyboard>

気を取り直して C# も元に戻します。

private void Button_Click_1(object sender, RoutedEventArgs e)
{
  scale.ScaleX = 1d;
  //((rectangle.RenderTransform as TransformGroup).Children[0] as ScaleTransform).ScaleX = 1d;		}

やっぱり動きません。。。orz

仕方がないので、rectangleから指定してみます。

private void Button_Click_1(object sender, RoutedEventArgs e)
{
  //scale.ScaleX = 1d;
  (rectangle.RenderTransform as ScaleTransform).ScaleX = 1;
}

いやー、腹立たしいくらい予想通りに元に戻ってくれますね!


疲れてきたので謎は謎のままにしておくってことで。。