.NET MAUIアプリについて「前編」でコンパイル、「中編」でサンプルコードのチェックをしました。今回は簡単なアプリを作って、レイアウトパネルの描画性能をWPFと比較してみます。
サンプル
ボールが飛び跳ねる様子を描画し、どれくらいのボール数まで耐えられるかを見てみます。
下の画像はWPFでボール100個を描画した場合です。アップロードサイズの都合で 15fps の画像ですが実際はもっとスムースに動きます。
mp4版
描画方法
絶対位置指定のできるレイアウトパネルにボール(Ellipse)を大量描画します。WPFは Canvas
、 MAUI は AbusoluteLayout
を使いました。
ボールはアニメーション機能を使わず、フレーム描画イベントごとに自前描写、位置を v = v0 + gt
という式で更新するだけです。そのコードは単純ですので省略します。(欲しい方いればgithubにでもアップします)
この先を読み進める前に・・・
レイアウトパネルの性能を見るためCanvas
やAbusoluteLayout
を使ってますが、本来レイアウトパネルはOwnerDrawでアニメをするものではないです。
この後出てくる数字を見て 「ゲームじゃ使えねえ!」「MAUIなにこれ!?」と思わないでほしいです・・・。MAUIにはGraphicViewという描画機能があるのでGraphicViewで描写テストした記事は別途投稿します。
WPFの場合
Xamlでキャンバスを張り付けボタンなどを事前に置いていきます。
実際のコードは座標指定やイベント処理が入ります。
<Window 省略 >
<Canvas x:Name="canvas">
<Button Content="Start" />
<Slider x:Name="slider" />
<TextBlock Text="{Binding ElementName=slider,Path=Value}" />
<TextBlock x:Name="fps" />
</Canvas>
</Window>
ボールはスライダーで個数指定させるためにC#で描画します。単純な丸いボールです。
var ellipse = new Ellipse {
Width = 5.0,
Height = 5.0,
Fill = Brushes.Black
};
canvas.Children.Add(ellipse);
ボタンを押されたら描画開始。WPFでは CompositionTarget.Rendering
でフレーム毎に描画をしますので呼ばれるたびにボールの位置をアップデートし、fpsを計算します。
private void Button_Click(object sender, RoutedEventArgs e)
{
CompositionTarget.Rendering += CompositionTarget_Rendering;
}
private void CompositionTarget_Rendering(object? sender, EventArgs e)
{
frame++;
foreach (var ball in _ballBist)
{
ball.UpdatePos(frame);
}
fps.Text = CalcFps();
私のPCではボール1000個ぐらいまでは60fps、2000個で約30fpsになります。
mp4版
.NET MAUIの場合
MAUIには以下の4つのレイアウト(公式HPの説明)があります。
絶対座標系として AbusoluteLayout
があるのでそれを使います。
位置はAbsoluteLayout.LayoutBounds
添付プロパティで指定します。
<AbsoluteLayout x:Name="a">
<Button Text="Start" AbsoluteLayout.LayoutBounds="400,5,200,33"/>
<Slider x:Name="slider" AbsoluteLayout.LayoutBounds="400,50"/>
<Label BindingContext="{x:Reference slider}" Text="{Binding Path=Value}"
AbsoluteLayout.LayoutBounds="400,80,200,25"/>
<Label x:Name="fps" />
</AbsoluteLayout>
ボールのフレーム毎描画もWPFと同じく CompositionTarget.Rendering
があったので使いました。もしかするとMAUIではもっと良い描画方法があるのかもしれません。
private void Button_Clicked(object sender, EventArgs e)
{
Microsoft.UI.Xaml.Media.CompositionTarget.Rendering += CompositionTarget_Rendering;
}
private void CompositionTarget_Rendering(object sender, object e)
{
frame++;
foreach (var ball in _list)
{
ball.UpdatePos(frame);
}
fps.Text = CalcFps();
}
MAUIでの動作状況は以下の通り。100個ぐらいで30fpsでした。
mp4版
残念な結果でしたのでGraphicViewで描写テストした記事を別途投稿します。
終わりに
本当はMVVMやMVU機能を書きたかったのですがなかなか時間が取れずお遊びにしました。
MAUIはXAML、データバインディング等は引き継がれているので、Xamarin経験者はほぼそのまま、WPFを作ったことがある人もそれほど違和感なく作れると思います。AndroidやiOS向けにXamarinを使ってしていた人は移行すると思います。
しかし、Windows向けGUIアプリを作りたいだけの場合、WinFormsやWPFから移行する動機が小さいと思いました。画面遷移機能などはとても便利なのですが。
描写性能についてはちゃんと本来の描画機能を使ったもので再度作ってみたいと思います。