xamlで宣言したImageをスクリプトから動かす

はじめに

  • 最近WPFを触ってるけど全く分からない
  • とりあえず機能単位のサンプルソースを自分で作ると理解した気になれた

やりたかったこと

やったこと

3通りの方法をやった

  1. データバインディングを用いて
  2. Canvasを用いて
  3. DynamicResorceを用いて

結果

  • 1は失敗
    • 最初の読み込み時は想定の場所に行くけど、以降動かない
  • 2は最低限のことはできたけど、Canvasのレイヤーの上でやる影響で色々厄介
  • 3がいい感じだった

どんなコードかいたのか

データバインディングを用いて

<Grid>
    <Label x:Name="target" Content="動くよ" Margin="{Binding position}" VerticalAlignment="Top" RenderTransformOrigin="0.349,-0.072" Height="50" Width="50"/>
</Grid>
public MainWindow(){
  InitializeComponent();
    // Thicknessは構造体だからこんな感じでいれる
    // 引数はフィールドに宣言か,直でいれるとその場所に表示される
  Thickness margin = new Thickness(left, top, right, bottom);
  this.DataContext = new { position = margin};
}

Canvasを用いて

<Grid Height="350" Width="525">
  <Canvas Height="350" Width="525">
     <Label x:Name="target" Content="動くよ" VerticalAlignment="Top" RenderTransformOrigin="0.349,-0.072" Height="50" Width="50" Canvas.Top="0" Canvas.Left="0"/>
</Grid>
// 引数にtopとleftをとって,その座標に移動する
private void MoveText(double top, double left) {
    Canvas.SetTop(target, top);
    Canvas.SetLeft(target, left);
}
  • Canvas.SetTop(変数名,top)でxamlで宣言されたCanvasタグに囲まれたオブジェクトをtopに移動
    • leftも同様
  • 引数の場所に移動出来たし,関数だからスクリプト内でループさせて移動させることができた
  • ただ,座標の比率が謎でpixelなげると変な挙動する
  • 一応動いたけど没

DynamicResorceを用いて

<Grid>
    <Label x:Name="target" Content="動くよ" Margin="{DynamicResource position}" VerticalAlignment="Top" RenderTransformOrigin="0.349,-0.072" Height="50" Width="50"/>
</Grid>
private void MoveText(double left,double top,double right,double bottom) {
    Thickness margin = new Thickness(left, top, right, bottom);
    this.Resources["textMargin"] = margin;
}
  • DynamicResourceはリソースの内容が変更されたら対象のプロパティも変更される
  • ただ,移動させるのにmarginを使ってるから,比率を変えないようにするのがめんどくさい
  • ちなみに,StaticResourceにすると一度しか値が適用されなくて,データバインディングを使った時みたいになった
  • これで行くことにした

DynamicResorceのデモつくった

解説

Update()の実装

 public MainWindow() {
     InitializeComponent();
     FixedTimeProcess();
 }

/// <summary>
/// 一定時間でDispatcherTimerTickを実行する関数
/// </summary>
private void FixedTimeProcess() {
    // 初期化
    dispatcherTimer = new DispatcherTimer(DispatcherPriority.Normal);
    // 左から 日数、時間、分、秒、ミリ秒で設定
    // 1ミリ秒ごとに30回実行
    dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 10);
    dispatcherTimer.Tick += new EventHandler(DispatcherTimerTick);
    dispatcherTimer.Start();
}

/// <summary>
/// FixedTimeProcessで実行される関数
/// </summary>
private void DispatcherTimerTick(object sender, EventArgs e) {
  // 一定時間毎に処理したい内容をここに記述
}
  • UnityのUpdate()見たいな関数を作りたかった

猫の画像を動かす

private void DispatcherTimerTick(object sender, EventArgs e) {

    catleft = (catleft < windowWidth / 2) ? catleft + 1 : -40;
    catright = (catleft < windowWidth / 2) ? catright - 1 : 240;

    MovePic(catleft, 84, catright, 84, "catMargin");
}

/// <summary>
/// テキストの大きさを変える関数
/// </summary>
private void MovePic(double left, double top, double right, double bottom, string target) {
    Thickness margin = new Thickness(left, top, right, bottom);
    this.Resources[target] = margin;
}
  • 今回は左から右に動かすだけだから,marginのtopとbottomは定数とした
  • marginのleftをインクリメントして,rightをデクリメントさせることで移動する
    • この時,画像本体の横幅が一定になるようにする
  • 画面の端に行ったらleftとrightを初期値に戻す
  • MovePic()は最初の4つの引数でmarginを設定する
    • 最後のstring型の引数で移動させたいtargetの名前をいれる