WPF 3Dトンネル効果、WPFでちょっとした賑わいを

WPF 3Dトンネル効果、WPFでちょっとした賑わいを

CSSやUWPと比較して、老舗のWPFでは3D効果の操作は比較的面倒です。まず3Dモデルを作成し、次にXY軸を回転させ、その後Z軸のストレッチを調整し、最後にFOVを調整します。トンネル効果はこのZ軸ストレッチの数値によって決まります。

最終更新 2022/02/21 13:58
ARM830
読了目安 11 分
カテゴリ
WPF
タグ
.NET WPF

CSS エフェクトのブログアドレス:

3D シューティング効果?CSS で簡単に実現 - ChokCoco - 博客园 (cnblogs.com)

UWP エフェクトのブログアドレス

3D シューティング効果?UWP でも実現可能 - dino.c - 博客园 (cnblogs.com)

皆さん、本当に達人ですね。

本当にたくさん学べることがあります。

私も便乗して、WPF で試してみました。効果はあまり良くありませんが、まあまあだと思います。

CSS や UWP に比べて、老舗の WPF は 3D 効果の操作が比較的煩雑です。まず 3D モデルを作成し、次に XY 軸を回転させ、Z 軸の伸縮を調整し、最後に FOV を調整します。シューティング効果はこの Z 軸の伸縮の数値で決まり、図では 10-20 です。

もちろん一番難しいのはアニメーションの最初と最後のつなぎです。

順を追ってやっていきましょう。

3D モデルの作成

この部分は 2D コントロールを使わずにそのまま 3D モデルにできるので、特に研究することはありません。画像をテクスチャとして貼り付けます。

3D モデルの作成についてまとめると、左から右へ進めることです。

  1. Positions

3D モデルは三角形で構成されるため、物体の形状を表すときはできるだけ三角形を描きます。各点が頂点で、同じ頂点が存在する場合は一つを選びます。

頂点を記述するときは XYZ で、物体を正面から見たとき、物体の Z 軸は自分に向かう方向が正方向です。Y 軸は上が正、X 軸は右が正です。

ここで注意すべき点は、便宜上、左、左下、右下、右上の順で点を定義することを推奨します。

このモデルの頂点定義は P1(x,y,z), P2(x,y,z), P3(x,y,z), P4(x,y,z) です。

  1. TriangleIndices

これは、これらの頂点がどのように三角形を構成するかを記述します。ある面を表面とみなす場合、頂点集合のインデックスを反時計回りに定義することを忘れないでください。頂点集合は Positions で、入力した座標点がその内容で、インデックスは 0 から始まります。

裏面は時計回りです。

  1. TextureCoordinates

これはマテリアルの位置指定順序で、これは 2D 座標系で他のものとは異なります。左上が 0,0、右下が 1,1、つまり通常の画面座標系です。

モデルを作成したら、4 つ作成する必要があります。

3D モデルの回転

これは少し面白いです。上記でモデルを 4 つ作成しましたが、4 つの面を構成するには、Y 軸回転、X 軸回転を行いますが、方向は異なります。回転には Transform を使用します。

まあまあに見えます。

4 つの画像を作成して試してみましょう。

デバッグしやすいように、プログレスバーを付けます。

リソース

<MeshGeometry3D x:Key="Rect3D_O">
  <MeshGeometry3D.Positions>
    -50, 50, 0, -50, -50, 0, 50, -50, 0, 50, 50, 0
  </MeshGeometry3D.Positions>
  <MeshGeometry3D.TriangleIndices> 0 1 2 2 3 0 </MeshGeometry3D.TriangleIndices>
  <MeshGeometry3D.TextureCoordinates>
    0,0 0,1 1,1 1,0
  </MeshGeometry3D.TextureCoordinates>
  <MeshGeometry3D.Normals> 0,0,1, 0,0,1, 0,0,1, 0,0,1 </MeshGeometry3D.Normals>
</MeshGeometry3D>
<DiffuseMaterial x:Key="Img">
  <DiffuseMaterial.Brush>
    <ImageBrush ImageSource="start.jpg" />
  </DiffuseMaterial.Brush>
</DiffuseMaterial>
<Viewport3D x:Name="View3D_2">
  <Viewport3D.Camera>
    <PerspectiveCamera
      FieldOfView="{Binding ElementName=FOV, Path=Value}"
      Position="0,0,100"
      LookDirection="0,0,-1"
    />
  </Viewport3D.Camera>
  <ModelVisual3D>
    <ModelVisual3D.Content>
      <Model3DGroup>
        <AmbientLight Color="White" />
        <GeometryModel3D
          Geometry="{StaticResource Rect3D_O}"
          Material="{StaticResource Img}"
          BackMaterial="{StaticResource Img}"
        >
          <GeometryModel3D.Transform>
            <Transform3DGroup>
              <RotateTransform3D CenterX="0" CenterY="1" CenterZ="0">
                <RotateTransform3D.Rotation>
                  <AxisAngleRotation3D
                    Angle="{Binding ElementName=Left_Top_Z, Path=Value}"
                    Axis="0 1 0"
                  />
                </RotateTransform3D.Rotation>
              </RotateTransform3D>
              <ScaleTransform3D
                ScaleZ="{Binding  ElementName=ScaleZ_2, Path=Value}"
              />
            </Transform3DGroup>
          </GeometryModel3D.Transform>
        </GeometryModel3D>
        <GeometryModel3D
          Geometry="{StaticResource Rect3D_O}"
          Material="{StaticResource Img}"
          BackMaterial="{StaticResource Img}"
        >
          <GeometryModel3D.Transform>
            <Transform3DGroup>
              <RotateTransform3D CenterX="0" CenterY="1" CenterZ="0">
                <RotateTransform3D.Rotation>
                  <AxisAngleRotation3D
                    Angle="{Binding ElementName=Left_Top_Z, Path=Value}"
                    Axis="1 0 0"
                  />
                </RotateTransform3D.Rotation>
              </RotateTransform3D>
              <ScaleTransform3D
                ScaleZ="{Binding  ElementName=ScaleZ_2, Path=Value}"
              />
            </Transform3DGroup>
          </GeometryModel3D.Transform>
        </GeometryModel3D>
        <GeometryModel3D
          Geometry="{StaticResource Rect3D_O}"
          Material="{StaticResource Img}"
          BackMaterial="{StaticResource Img}"
        >
          <GeometryModel3D.Transform>
            <Transform3DGroup>
              <RotateTransform3D CenterX="0" CenterY="1" CenterZ="0">
                <RotateTransform3D.Rotation>
                  <AxisAngleRotation3D
                    Angle="{Binding ElementName=Right_Bottom_Z, Path=Value}"
                    Axis="0 1 0"
                  />
                </RotateTransform3D.Rotation>
              </RotateTransform3D>
              <ScaleTransform3D
                ScaleZ="{Binding  ElementName=ScaleZ_2, Path=Value}"
              />
            </Transform3DGroup>
          </GeometryModel3D.Transform>
        </GeometryModel3D>
        <GeometryModel3D
          Geometry="{StaticResource Rect3D_O}"
          Material="{StaticResource Img}"
          BackMaterial="{StaticResource Img}"
        >
          <GeometryModel3D.Transform>
            <Transform3DGroup>
              <RotateTransform3D CenterX="0" CenterY="1" CenterZ="0">
                <RotateTransform3D.Rotation>
                  <AxisAngleRotation3D
                    Angle="{Binding ElementName=Right_Bottom_Z, Path=Value}"
                    Axis="1 0 0"
                  />
                </RotateTransform3D.Rotation>
              </RotateTransform3D>
              <ScaleTransform3D
                ScaleZ="{Binding  ElementName=ScaleZ_2, Path=Value}"
              />
            </Transform3DGroup>
          </GeometryModel3D.Transform>
        </GeometryModel3D>
      </Model3DGroup>
    </ModelVisual3D.Content>
  </ModelVisual3D>
</Viewport3D>

<Slider
  Grid.Row="1"
  x:Name="Left_Top_Z"
  Minimum="-90"
  Value="12"
  Maximum="90"
  ToolTip="{Binding  RelativeSource={RelativeSource Mode=Self}, Path=Value}"
/>
<Slider
  Grid.Row="2"
  x:Name="Right_Bottom_Z"
  Minimum="-90"
  Value="-12"
  Maximum="0"
  ToolTip="{Binding  RelativeSource={RelativeSource Mode=Self}, Path=Value}"
/>
<Slider
  Grid.Row="3"
  x:Name="ScaleZ_2"
  Background="Red"
  Minimum="10"
  Maximum="100"
  ToolTip="{Binding  RelativeSource={RelativeSource Mode=Self}, Path=Value}"
>
  <Slider.Style>
    <style TargetType="Slider">
      <Style.Triggers>
          <Trigger Property="Tag" Value="1">
              <Trigger.EnterActions>
                  <BeginStoryboard >
                      <Storyboard>
                          <DoubleAnimation  RepeatBehavior="Forever"  Storyboard.TargetProperty="Value"   From="11" To="20" BeginTime="0:0:0"   Duration="0:0:10" />
                      </Storyboard>
                  </BeginStoryboard>
              </Trigger.EnterActions>
          </Trigger>
      </Style.Triggers>
    </style>
  </Slider.Style>
</Slider>
<Slider
  Grid.Row="4"
  x:Name="FOV"
  Minimum="0"
  Maximum="180"
  Value="176"
  ToolTip="{Binding  RelativeSource={RelativeSource Mode=Self}, Path=Value}"
/>

実行して確認します。

なんとなくそれらしくなってきました。

残りはアニメーションの調整です。

最初と最後をつなぐアニメーションを実現したい場合、実際には 2 つのアニメーションの最初と最後に違いが見えないようにする必要があります。先輩方の基本的な考え方を参考に、透明度と遅延再生を利用して、最初と最後の違いを分からなくします。

つまり、次のようにする必要があります。

ここでは、この方式を XAML だけで実装します。

まず、タイミングの問題を解決する必要があります。ページ読み込み時に、アニメーションであるオブジェクトの特定の値を変更します。そのオブジェクトにはトリガーがあり、このオブジェクトを監視してタイマーを開始し、その後アニメーションを再生します。

値の変更には、ObjectAnimationUsingKeyFrames アニメーションを使用します。

トリガーは値トリガーで、バインドできるためです。

全体のプロセスで最も重要なのはタイムラインで、2 つのアニメーショングループがいつ表示され、いつ非表示になるかです。

最終コード

<Window.Resources>
  <Storyboard
    RepeatBehavior="Forever"
    Storyboard.TargetName="ScaleZ_2"
    Duration="0:0:10"
    x:Key="sb"
  >
    <DoubleAnimation
      Storyboard.TargetName="ScaleZ_2"
      Storyboard.TargetProperty="Value"
      From="11"
      To="20"
      BeginTime="0:0:0"
      Duration="0:0:10"
    />
    <DoubleAnimationUsingKeyFrames
      Storyboard.TargetProperty="Opacity"
      Storyboard.TargetName="View3D_2"
      BeginTime="0:0:0"
    >
      <LinearDoubleKeyFrame KeyTime="0:0:0" Value="0" />
      <LinearDoubleKeyFrame KeyTime="0:0:2" Value="1" />
      <LinearDoubleKeyFrame KeyTime="0:0:6" Value="1" />
      <LinearDoubleKeyFrame KeyTime="0:0:10" Value="0" />
    </DoubleAnimationUsingKeyFrames>
  </Storyboard>
  <MeshGeometry3D x:Key="Rect3D_O">
    <MeshGeometry3D.Positions>
      -50, 50, 0, -50, -50, 0, 50, -50, 0, 50, 50, 0
    </MeshGeometry3D.Positions>
    <MeshGeometry3D.TriangleIndices>
      0 1 2 2 3 0
    </MeshGeometry3D.TriangleIndices>
    <MeshGeometry3D.TextureCoordinates>
      0,0 0,1 1,1 1,0
    </MeshGeometry3D.TextureCoordinates>
    <MeshGeometry3D.Normals>
      0,0,1, 0,0,1, 0,0,1, 0,0,1
    </MeshGeometry3D.Normals>
  </MeshGeometry3D>
  <DiffuseMaterial x:Key="Img">
    <DiffuseMaterial.Brush>
      <ImageBrush ImageSource="start.jpg" />
    </DiffuseMaterial.Brush>
  </DiffuseMaterial>
</Window.Resources>
<Window.Triggers>
  <EventTrigger RoutedEvent="Loaded" SourceName="ScaleZ">
    <BeginStoryboard>
      <Storyboard
        Storyboard.TargetName="ScaleZ"
        Storyboard.TargetProperty="Tag"
        Duration="0:0:5.1"
      >
        <ObjectAnimationUsingKeyFrames>
          <DiscreteObjectKeyFrame KeyTime="0:0:5">
            <DiscreteObjectKeyFrame.Value> 1 </DiscreteObjectKeyFrame.Value>
          </DiscreteObjectKeyFrame>
        </ObjectAnimationUsingKeyFrames>
      </Storyboard>
    </BeginStoryboard>
    <BeginStoryboard Storyboard="{StaticResource sb}" />
  </EventTrigger>
</Window.Triggers>
<Grid>
  <Grid.RowDefinitions>
    <RowDefinition />
    <RowDefinition Height="auto" />
    <RowDefinition Height="auto" />
    <RowDefinition Height="auto" />
    <RowDefinition Height="auto" />
    <RowDefinition Height="auto" />
    <RowDefinition Height="auto" />
  </Grid.RowDefinitions>
  <Viewport3D x:Name="View3D_1">
    <Viewport3D.Style>
      <style TargetType="Viewport3D">
        <Style.Triggers>
            <DataTrigger Binding="{Binding ElementName=ScaleZ,Path=Value}" Value="1">
                <DataTrigger.EnterActions>
                    <BeginStoryboard >
                        <Storyboard>
                            <DoubleAnimationUsingKeyFrames  RepeatBehavior="Forever" Storyboard.TargetProperty="Opacity"  BeginTime="0:0:0"  Duration="0:0:10">
                                <LinearDoubleKeyFrame KeyTime="0:0:0" Value="0"/>
                                <LinearDoubleKeyFrame KeyTime="0:0:5" Value="1"/>
                                <LinearDoubleKeyFrame KeyTime="0:0:8" Value="1"/>
                                <LinearDoubleKeyFrame KeyTime="0:0:10" Value="0"/>
                            </DoubleAnimationUsingKeyFrames>
                        </Storyboard>
                    </BeginStoryboard>
                </DataTrigger.EnterActions>
            </DataTrigger>
        </Style.Triggers>
      </style>
    </Viewport3D.Style>
    <Viewport3D.Camera>
      <PerspectiveCamera
        FieldOfView="{Binding ElementName=FOV, Path=Value}"
        Position="0,0,100"
        LookDirection="0,0,-1"
      />
    </Viewport3D.Camera>
    <ModelVisual3D>
      <ModelVisual3D.Content>
        <Model3DGroup>
          <AmbientLight Color="White" />
          <GeometryModel3D
            Geometry="{StaticResource Rect3D_O}"
            Material="{StaticResource Img}"
            BackMaterial="{StaticResource Img}"
          >
            <GeometryModel3D.Transform>
              <Transform3DGroup>
                <RotateTransform3D CenterX="0" CenterY="1" CenterZ="0">
                  <RotateTransform3D.Rotation>
                    <AxisAngleRotation3D
                      Angle="{Binding ElementName=Left_Top_Z, Path=Value}"
                      Axis="0 1 0"
                    />
                  </RotateTransform3D.Rotation>
                </RotateTransform3D>
                <ScaleTransform3D
                  ScaleZ="{Binding  ElementName=ScaleZ, Path=Value}"
                />
              </Transform3DGroup>
            </GeometryModel3D.Transform>
          </GeometryModel3D>
          <GeometryModel3D
            Geometry="{StaticResource Rect3D_O}"
            Material="{StaticResource Img}"
            BackMaterial="{StaticResource Img}"
          >
            <GeometryModel3D.Transform>
              <Transform3DGroup>
                <RotateTransform3D CenterX="0" CenterY="1" CenterZ="0">
                  <RotateTransform3D.Rotation>
                    <AxisAngleRotation3D
                      Angle="{Binding ElementName=Left_Top_Z, Path=Value}"
                      Axis="1 0 0"
                    />
                  </RotateTransform3D.Rotation>
                </RotateTransform3D>
                <ScaleTransform3D
                  ScaleZ="{Binding  ElementName=ScaleZ, Path=Value}"
                />
              </Transform3DGroup>
            </GeometryModel3D.Transform>
          </GeometryModel3D>
          <GeometryModel3D
            Geometry="{StaticResource Rect3D_O}"
            Material="{StaticResource Img}"
            BackMaterial="{StaticResource Img}"
          >
            <GeometryModel3D.Transform>
              <Transform3DGroup>
                <RotateTransform3D CenterX="0" CenterY="1" CenterZ="0">
                  <RotateTransform3D.Rotation>
                    <AxisAngleRotation3D
                      Angle="{Binding ElementName=Right_Bottom_Z, Path=Value}"
                      Axis="0 1 0"
                    />
                  </RotateTransform3D.Rotation>
                </RotateTransform3D>
                <ScaleTransform3D
                  ScaleZ="{Binding  ElementName=ScaleZ, Path=Value}"
                />
              </Transform3DGroup>
            </GeometryModel3D.Transform>
          </GeometryModel3D>
          <GeometryModel3D
            Geometry="{StaticResource Rect3D_O}"
            Material="{StaticResource Img}"
            BackMaterial="{StaticResource Img}"
          >
            <GeometryModel3D.Transform>
              <Transform3DGroup>
                <RotateTransform3D CenterX="0" CenterY="1" CenterZ="0">
                  <RotateTransform3D.Rotation>
                    <AxisAngleRotation3D
                      Angle="{Binding ElementName=Right_Bottom_Z, Path=Value}"
                      Axis="1 0 0"
                    />
                  </RotateTransform3D.Rotation>
                </RotateTransform3D>
                <ScaleTransform3D
                  ScaleZ="{Binding  ElementName=ScaleZ, Path=Value}"
                />
              </Transform3DGroup>
            </GeometryModel3D.Transform>
          </GeometryModel3D>
        </Model3DGroup>
      </ModelVisual3D.Content>
    </ModelVisual3D>
  </Viewport3D>
  <Viewport3D x:Name="View3D_2">
    <Viewport3D.Camera>
      <PerspectiveCamera
        FieldOfView="{Binding ElementName=FOV, Path=Value}"
        Position="0,0,100"
        LookDirection="0,0,-1"
      />
    </Viewport3D.Camera>
    <ModelVisual3D>
      <ModelVisual3D.Content>
        <Model3DGroup>
          <AmbientLight Color="White" />
          <GeometryModel3D
            Geometry="{StaticResource Rect3D_O}"
            Material="{StaticResource Img}"
            BackMaterial="{StaticResource Img}"
          >
            <GeometryModel3D.Transform>
              <Transform3DGroup>
                <RotateTransform3D CenterX="0" CenterY="1" CenterZ="0">
                  <RotateTransform3D.Rotation>
                    <AxisAngleRotation3D
                      Angle="{Binding ElementName=Left_Top_Z, Path=Value}"
                      Axis="0 1 0"
                    />
                  </RotateTransform3D.Rotation>
                </RotateTransform3D>
                <ScaleTransform3D
                  ScaleZ="{Binding  ElementName=ScaleZ_2, Path=Value}"
                />
              </Transform3DGroup>
            </GeometryModel3D.Transform>
          </GeometryModel3D>
          <GeometryModel3D
            Geometry="{StaticResource Rect3D_O}"
            Material="{StaticResource Img}"
            BackMaterial="{StaticResource Img}"
          >
            <GeometryModel3D.Transform>
              <Transform3DGroup>
                <RotateTransform3D CenterX="0" CenterY="1" CenterZ="0">
                  <RotateTransform3D.Rotation>
                    <AxisAngleRotation3D
                      Angle="{Binding ElementName=Left_Top_Z, Path=Value}"
                      Axis="1 0 0"
                    />
                  </RotateTransform3D.Rotation>
                </RotateTransform3D>
                <ScaleTransform3D
                  ScaleZ="{Binding  ElementName=ScaleZ_2, Path=Value}"
                />
              </Transform3DGroup>
            </GeometryModel3D.Transform>
          </GeometryModel3D>
          <GeometryModel3D
            Geometry="{StaticResource Rect3D_O}"
            Material="{StaticResource Img}"
            BackMaterial="{StaticResource Img}"
          >
            <GeometryModel3D.Transform>
              <Transform3DGroup>
                <RotateTransform3D CenterX="0" CenterY="1" CenterZ="0">
                  <RotateTransform3D.Rotation>
                    <AxisAngleRotation3D
                      Angle="{Binding ElementName=Right_Bottom_Z, Path=Value}"
                      Axis="0 1 0"
                    />
                  </RotateTransform3D.Rotation>
                </RotateTransform3D>
                <ScaleTransform3D
                  ScaleZ="{Binding  ElementName=ScaleZ_2, Path=Value}"
                />
              </Transform3DGroup>
            </GeometryModel3D.Transform>
          </GeometryModel3D>
          <GeometryModel3D
            Geometry="{StaticResource Rect3D_O}"
            Material="{StaticResource Img}"
            BackMaterial="{StaticResource Img}"
          >
            <GeometryModel3D.Transform>
              <Transform3DGroup>
                <RotateTransform3D CenterX="0" CenterY="1" CenterZ="0">
                  <RotateTransform3D.Rotation>
                    <AxisAngleRotation3D
                      Angle="{Binding ElementName=Right_Bottom_Z, Path=Value}"
                      Axis="1 0 0"
                    />
                  </RotateTransform3D.Rotation>
                </RotateTransform3D>
                <ScaleTransform3D
                  ScaleZ="{Binding  ElementName=ScaleZ_2, Path=Value}"
                />
              </Transform3DGroup>
            </GeometryModel3D.Transform>
          </GeometryModel3D>
        </Model3DGroup>
      </ModelVisual3D.Content>
    </ModelVisual3D>
  </Viewport3D>

  <Slider
    Grid.Row="1"
    x:Name="Left_Top_Z"
    Minimum="-90"
    Value="12"
    Maximum="90"
    ToolTip="{Binding  RelativeSource={RelativeSource Mode=Self}, Path=Value}"
  />
  <Slider
    Grid.Row="2"
    x:Name="Right_Bottom_Z"
    Minimum="-90"
    Value="-12"
    Maximum="0"
    ToolTip="{Binding  RelativeSource={RelativeSource Mode=Self}, Path=Value}"
  />
  <Slider
    Grid.Row="3"
    x:Name="ScaleZ"
    Background="Red"
    Minimum="10"
    Maximum="100"
    ToolTip="{Binding  RelativeSource={RelativeSource Mode=Self}, Path=Value}"
  >
    <Slider.Style>
      <style TargetType="Slider">
        <Style.Triggers>
            <Trigger Property="Tag" Value="1">
                <Trigger.EnterActions>
                    <BeginStoryboard >
                        <Storyboard>
                            <DoubleAnimation  RepeatBehavior="Forever"  Storyboard.TargetProperty="Value"   From="11" To="20" BeginTime="0:0:0"   Duration="0:0:10" />
                        </Storyboard>
                    </BeginStoryboard>
                </Trigger.EnterActions>
            </Trigger>
        </Style.Triggers>
      </style>
    </Slider.Style>
  </Slider>
  <Slider
    Grid.Row="4"
    x:Name="FOV"
    Minimum="0"
    Maximum="180"
    Value="176"
    ToolTip="{Binding  RelativeSource={RelativeSource Mode=Self}, Path=Value}"
  />
  <Slider
    Grid.Row="5"
    x:Name="ScaleZ_2"
    Background="Black"
    Minimum="10"
    Maximum="100"
    ToolTip="{Binding  RelativeSource={RelativeSource Mode=Self}, Path=Value}"
  />
  <StackPanel Grid.Row="6" Orientation="Vertical">
    <TextBlock>
      <Run Text=" View3D_1 透明度" />
      <Run Text="{Binding ElementName=View3D_1, Path=Opacity}" />
      <Run Text=" View3D_1 value" />
      <Run Text="{Binding ElementName=ScaleZ, Path=Value}" />
      <Run Text=" Tag value" />
      <Run Text="{Binding ElementName=ScaleZ, Path=Tag}" />
      <Run Text=" Zindex value" />
      <Run Text="{Binding ElementName=View3D_1, Path=(Panel.ZIndex)}" />
    </TextBlock>
    <TextBlock>
      <Run Text=" View3D_2 透明度" />
      <Run Text="{Binding ElementName=View3D_2, Path=Opacity}" />
      <Run Text=" View3D_2 value" />
      <Run Text="{Binding ElementName=ScaleZ_2, Path=Value}" />
      <Run Text=" Zindex value" />
      <Run Text="{Binding ElementName=View3D_2, Path=(Panel.ZIndex)}" />
    </TextBlock>
  </StackPanel>
</Grid>

こうすることで、C# コードを一切使わずにこの効果を実現できます。

ただし、開始の 0 秒の部分はあまりうまくできておらず、少しゴーストが出ています。まだまだ学ぶべきことがたくさんあります。

さらに探索

関連読書

その他の記事
同じカテゴリ / 同じタグ 2025/09/13

WPF から Avalonia への移行シリーズ:なぜ WPF プログラムを Avalonia に移行しなければならないのか

過去数年間、当社の上位機ソフトウェアは主に WPF と WinForm で開発されてきました。これらの技術は Windows プラットフォームで非常に便利であり、小規模試作から現在の規模拡大による納品まで、私たちを支えてきました。しかし、ビジネスの発展や顧客ニーズの変化に伴い、単一の Windows テクノロジースタックは私たちが必ず乗り越えなければならない壁となってきました。

続きを読む
同じカテゴリ / 同じタグ 2025/01/26

WPF カスタムXMLファイルによる国際化

この記事では、WPFプログラムでカスタムXMLファイルを使用して国際化を実現する方法について詳しく説明します。必要なNuGetパッケージのインストール、言語リストの動的取得、言語の動的切り替え、コードおよびXAMLインターフェースでの翻訳文字列の使用などを含み、ソースコードのリンクも提供し、開発者がWPFアプリケーションの国際化を簡単に実装できるように支援します。

続きを読む