ユーザ用ツール

サイト用ツール


ハイハイスクールアドベンチャー_avaloniaui版

差分

このページの2つのバージョン間の差分を表示します。

この比較画面へのリンク

両方とも前のリビジョン前のリビジョン
次のリビジョン
前のリビジョン
ハイハイスクールアドベンチャー_avaloniaui版 [2025/10/14 01:48] – [AvaloniaUI版への困難な道] arakiハイハイスクールアドベンチャー_avaloniaui版 [2025/10/16 23:02] (現在) – [カスタムスタイルにテーマは適用できない?] araki
行 27: 行 27:
 しかし、これがそんなに甘くはないんだということに気づくのに、それほど時間は必要ではありませんでした。 しかし、これがそんなに甘くはないんだということに気づくのに、それほど時間は必要ではありませんでした。
  
 +<del>なお、2025年10月14日現在、まだ完成に至っていません。
 +ゲームはできるんですが、設定画面が全く動かなくて……。</del>
 +
 +{{::hhsadvava:hhsadvavalonia.png?400|}}
 ===== AvaloniaUI版への困難な道 ===== ===== AvaloniaUI版への困難な道 =====
  
行 51: 行 55:
 似たような話は Androidでもあったので、まあ、それはそれなんですが、処理の受け渡しなどの作法が、AIに聞きながらやっていると、それじゃないというコードが出てきたりして、ちょっと手間がかかりました。 似たような話は Androidでもあったので、まあ、それはそれなんですが、処理の受け渡しなどの作法が、AIに聞きながらやっていると、それじゃないというコードが出てきたりして、ちょっと手間がかかりました。
  
 +<code c#>
 +        public async Task UpdateScreenAndAwaitRenderAsync()
 +        {
 +            // 1. TaskCompletionSource を作成し、イベントの完了を待てるようにする
 +            var tcs = new TaskCompletionSource<bool>();
 +            
 +            // 2. イベントハンドラを定義し、発火したら Task を完了させる
 +            //    C#のイベントハンドラは、イベントが発生した後に自身を解除します。
 +            EventHandler handler = null!;
 +            
 +            handler = (s, e) =>
 +            {
 +                // UIスレッドで実行されているため、直接操作して問題ありません。
 +                // イベントハンドラを解除
 +                Screen.LayoutUpdated -= handler; 
 +                // 待機中の Task を完了させる
 +                tcs.TrySetResult(true); 
 +            };
 +
 +            // 3. イベントハンドラを登録し、ソースを更新
 +            Screen.LayoutUpdated += handler;
 +            Screen.InvalidateVisual(); // 画面更新を要求
 +
 +            // 4. Taskが完了するまで待機 (描画完了まで待機)
 +            await tcs.Task;
 +        }
 +</code>
 +
 +画面の書き換えが終わったら上をawait指定で呼び出す。
 +
 +<code c#>
 +await UpdateScreenAndAwaitRenderAsync();
 +</code>
 ==== モーダルダイアログ ==== ==== モーダルダイアログ ====
  
行 78: 行 115:
 Qtでも WPFでも、設定ダイアログのコードビハインドでこのあたりの処理をしていたんですが、設定値は ModelView をつかって、設定画面の DataContext としてマッピングして、サービスを介在させて、親画面に変更が伝わるようにすればいい、ということらしいのですが、そのようにやったとたんにビルドすら通らなくなりました。 Qtでも WPFでも、設定ダイアログのコードビハインドでこのあたりの処理をしていたんですが、設定値は ModelView をつかって、設定画面の DataContext としてマッピングして、サービスを介在させて、親画面に変更が伝わるようにすればいい、ということらしいのですが、そのようにやったとたんにビルドすら通らなくなりました。
  
-結論から言うと、Avalonia.ReactiveUI のパッケージと、その依存しているパッケージの間に不整合があって、結果、ビルドできなかったり例外はいたりと様々な問題を引き起こしていました。+<del>結論から言うと、Avalonia.ReactiveUI のパッケージと、その依存しているパッケージの間に不整合があって、結果、ビルドできなかったり例外はいたりと様々な問題を引き起こしていました。
  
 AIは、あれなおせ、これなおせ、といっていろいろ示唆をくれるのですが、こういう状況ではしばしばループに陥って、正解にたどり着けなくなるので、こっちからも「こうじゃないの?ああじゃないの?」というのを入れていかないといけません。 AIは、あれなおせ、これなおせ、といっていろいろ示唆をくれるのですが、こういう状況ではしばしばループに陥って、正解にたどり着けなくなるので、こっちからも「こうじゃないの?ああじゃないの?」というのを入れていかないといけません。
  
-結局のところ、Avalonia.ReactiveUIは捨てて、ReactiveUIの機能だけを使って、残りは手で実装しよう、とかいうことになりまして、実はここの部分はまだ進行中なのです。+結局のところ、Avalonia.ReactiveUIは捨てて、ReactiveUIの機能だけを使って、残りは手で実装しよう、とかいうことになりまして、実はここの部分はまだ進行中なのです。</del> 
 + 
 +Copilotのいうままにパッケージをあれこれ追加していたら、Geminiが、ReactiveUIとか直接関係ないやつはパッケージマネージャに任せて指定すんな!っていうのでそうしたらあっさりビルド問題は解決しました。 
 + 
 +あとは、構造を整理して、きちんと動くようになりました。 
 + 
 +==== スクロールバーが出ない? ==== 
 + 
 +ハイハイスクールアドベンチャーでは、画面の下部にメッセージビューを置いて、長くなったらスクロールバーが出るようにしているのですが、これがメッセージがいくら長くなっても出てこないのです。 
 + 
 +おかしいでしょう? 
 + 
 +結論から言うと StackPanelを使っていると、ログビュワーの縦方向が無限に長い扱いになるらしくて、スクロール必要にならない。 
 +なので、StackPanelじゃなくて Gridを使いましょうという結論なわけです。 
 +わからんよ、そんなの! 
 + 
 +==== 色味違わない? ==== 
 + 
 +色コードの扱いの違いなのか、同じロジックで実装しているのに、他の環境と微妙に色味が違っている部分があるような気がします。 
 + 
 +{{:hhsadvava:isako.png?400|}}{{::hhsadvwin:isako.png?400|}} 
 + 
 +上がAvaloniaUI版で下がWPF版です。 
 +ほかのプラットフォームでも下と似た色味になるので、AvaloniaUIの一部の色の処理が少し違っているのかなあと思っています。 
 + 
 +==== カスタムスタイルにテーマは適用できない? ==== 
 + 
 +設定ダイアログで、チェックボックスはスライドスイッチに、ラジオボタンは押しボタン風にしたいわけです。 
 +環境によってはそもそもサポートされていたり、カスタムコードを書いたり、あるいはスタイルを書き換えるだけで実現できたりと様々ですが、AvaloniaUIではカスタムスタイルを作って適用するだけで外観を変更することができます。 
 + 
 +色はテーマに追随してほしいので、AIにそのように頼むと「簡単です」とかいいながら、FluentTheme と同じになります、とかいってカスタムスタイルに色設定を埋め込んでいくのですがこれが全くと言っていいほど効かない。 
 + 
 +即値を指定すれば反映されるから、テーマカラーをうまく拾えないのが原因なのは明らかなので、自前でブラシを定義して、テーマによって同じ名前に違う色を割り当ててくれればそれでいいよっていっているのに、AIが頑固にテーマカラーを適用する方法を模索し続けるものだからもう大変。 
 + 
 +最終的にAIが折れて、自前のブラシをテーマごとに用意する方向で実装となりました。 
 + 
 +{{::hhsadvava:preferences_ng.png?400|}}{{::hhsadvava:preferences_ok.png?400|}} 
 + 
 +テーマカラーを使おうとすると上のようになり、自前のブラシを使うようにしてようやく下のようにすることができました。 
 + 
 +<code xml> 
 +        <Style Selector=":is(Control):light"> 
 +            <Style.Resources> 
 +                <SolidColorBrush x:Key="PushButton.Background.Normal" Color="#EBEBEB"/> 
 +                <SolidColorBrush x:Key="PushButton.Border.Normal" Color="#DADADA"/> 
 +                <SolidColorBrush x:Key="PushButton.Foreground.Normal" Color="#7F7F7F"/> 
 +                <SolidColorBrush x:Key="PushButton.Background.Checked" Color="#0078D4"/> 
 +                <SolidColorBrush x:Key="PushButton.Foreground.Checked" Color="White"/> 
 +                <SolidColorBrush x:Key="PushButton.Background.PointerOver" Color="#F4F4F4"/> 
 +            </Style.Resources> 
 +        </Style> 
 + 
 +        <Style Selector=":is(Control):dark"> 
 +            <Style.Resources> 
 +                <SolidColorBrush x:Key="PushButton.Background.Normal" Color="#2D2D2D"/> 
 +                <SolidColorBrush x:Key="PushButton.Border.Normal" Color="#4D4D4D"/> 
 +                <SolidColorBrush x:Key="PushButton.Foreground.Normal" Color="White"/> 
 +                <SolidColorBrush x:Key="PushButton.Background.Checked" Color="#0078D4"/> 
 +                <SolidColorBrush x:Key="PushButton.Foreground.Checked" Color="White"/> 
 +                <SolidColorBrush x:Key="PushButton.Background.PointerOver" Color="#383838"/> 
 +            </Style.Resources> 
 +        </Style> 
 +</code> 
 + 
 +これでlight用、dark用の色を分けられるので、このブラシを使ってカスタムスタイルを作ればうまくいきます。 
 + 
 +<file xml CustomStyles.axaml> 
 +<Styles xmlns="https://github.com/avaloniaui" 
 +        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 
 + 
 +    <!-- スイッチスタイル --> 
 +    <Style Selector="ToggleButton.ToggleSwitch"> 
 +      <Setter Property="Template"> 
 +        <ControlTemplate> 
 +          <Border Width="50" Height="25" CornerRadius="12.5" 
 +                  Background="{TemplateBinding Background}"> 
 +            <Grid> 
 +              <!-- サム --> 
 +              <Border x:Name="PART_Knob" 
 +                      Width="21" Height="21" 
 +                      CornerRadius="10.5" 
 +                      Background="White" 
 +                      HorizontalAlignment="Left" 
 +                      Margin="2"/> 
 +            </Grid> 
 +          </Border> 
 +        </ControlTemplate> 
 +      </Setter> 
 +      <Setter Property="Background" Value="LightGray"/> 
 +    </Style> 
 + 
 +    <!-- チェック時の見た目 --> 
 +    <Style Selector="ToggleButton.ToggleSwitch:checked"> 
 +      <Setter Property="Background" Value="MediumSeaGreen"/> 
 +    </Style> 
 +    <Style Selector="ToggleButton.ToggleSwitch:checked /template/ Border#PART_Knob"> 
 +      <Setter Property="HorizontalAlignment" Value="Right"/> 
 +    </Style> 
 + 
 + 
 +    <!-- 押しボタン風 RadioButton --> 
 +    <Style Selector="RadioButton.PushButtonStyle"> 
 +        <Setter Property="Template"> 
 +            <ControlTemplate> 
 +                <Border x:Name="PART_Border" 
 +                        Padding="8" 
 +                        Background="{TemplateBinding Background}" 
 +                        BorderBrush="{TemplateBinding BorderBrush}" 
 +                        BorderThickness="1" 
 +                        CornerRadius="4"> 
 +                    <ContentPresenter Content="{TemplateBinding Content}" 
 +                                      ContentTemplate="{TemplateBinding ContentTemplate}" 
 +                                      Foreground="{TemplateBinding Foreground}"  
 +                                      HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
 +                                      VerticalAlignment="{TemplateBinding VerticalContentAlignment}" 
 +                                      RecognizesAccessKey="True"/> 
 +                </Border> 
 +            </ControlTemplate> 
 +    </Setter> 
 + 
 +    <Setter Property="Foreground" Value="{StaticResource PushButton.Foreground.Normal}"/> 
 +        <Setter Property="Background" Value="{StaticResource PushButton.Background.Normal}"/> 
 +        <Setter Property="BorderBrush" Value="{StaticResource PushButton.Border.Normal}"/> 
 +    </Style> 
 + 
 +    <Style Selector="RadioButton.PushButtonStyle:pointerover"> 
 +        <Setter Property="Background" Value="{StaticResource PushButton.Background.PointerOver}"/> 
 +        <Setter Property="BorderBrush" Value="{StaticResource PushButton.Border.Normal}"/> 
 +    </Style> 
 + 
 +    <Style Selector="RadioButton.PushButtonStyle:pressed"> 
 +        <Setter Property="Background" Value="{StaticResource PushButton.Background.PointerOver}"/> 
 +    </Style> 
 + 
 +    <Style Selector="RadioButton.PushButtonStyle:checked"> 
 +        <Setter Property="Background" Value="{StaticResource PushButton.Background.Checked}"/> 
 +        <Setter Property="BorderBrush" Value="{StaticResource PushButton.Background.Checked}"/> 
 +        <Setter Property="Foreground" Value="{StaticResource PushButton.Foreground.Checked}"/> 
 +    </Style> 
 + 
 +    <Style Selector="RadioButton.PushButtonStyle:checked:pointerover"> 
 +        <Setter Property="Background" Value="{StaticResource PushButton.Background.Checked}"/> 
 +        <Setter Property="BorderBrush" Value="{StaticResource PushButton.Background.Checked}"/> 
 +    </Style> 
 + 
 +    <Style Selector="RadioButton.PushButtonStyle:disabled"> 
 +        <Setter Property="Background" Value="{DynamicResource ThemeControlLowBrush}"/> 
 +        <Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderLowBrush}"/> 
 +        <Setter Property="Foreground" Value="{DynamicResource ThemeForegroundDisabledBrush}"/> 
 +    </Style> 
 +</Styles> 
 +</file>
  
 +===== AvaloniaUIの良いところ =====
  
  
 +==== テーマの統一的検出機能 ====
  
 +WPFやQtの6.8以前はレジストリをじか読みしたり、GNOMEの設定ファイルを読んだりしないとシステムのテーマを取り出せないというめんどくささがあったのですが、AvaloniaUIは、機種に依存しない取得方法と設定方法の両方を提供しています。
  
 +また、独自テーマを作る際にも、XAMLのような辞書方式や、Qtのスタイルシート方式のどちらでもできるらしく、柔軟性に優れています。
  
  
  
ハイハイスクールアドベンチャー_avaloniaui版.1760406507.txt.gz · 最終更新: by araki