🎨

.NET MAUI スタイリングメモ

に公開

はじめに

.NET MAUI アプリ開発でUIを作るときのメモ。


1. DataTemplate

  • リストやカードの見た目を定義する。
  • オブジェクトをバインドする場合、どのプロパティを表示するかを定義。

https://learn.microsoft.com/ja-jp/dotnet/maui/fundamentals/datatemplate

表示用のクラス
TodoItem.cs
public class TodoItem
{
    public string Title { get; set; }
    public string Note { get; set; }
    public bool Done { get; set; }
}
<CollectionView ItemsSource="{Binding Items}"
                SelectionMode="Single"
                ItemSizingStrategy="MeasureFirstItem">
    <CollectionView.ItemTemplate>
    <DataTemplate x:DataType="models:TodoItem">
        <Grid Padding="12" ColumnDefinitions="*,Auto">
            <StackLayout Grid.Column="0">
                <Label Text="{Binding Title}" Style="{DynamicResource Key=AccentLabel}" FontAttributes="Bold"/>
                <Label Text="{Binding Note}" Grid.Row="1" Opacity="0.8"/>
            </StackLayout>

            <Button Grid.Column="1"
                Text="Detail" 
                Command="{Binding Source={RelativeSource AncestorType={x:Type ContentPage}}, Path=BindingContext.ShowDetailCommand}"
                CommandParameter="{Binding .}" />
        </Grid>
    </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

2. Style / ResourceDictionary

  • 見た目を共通化・テーマ対応

https://learn.microsoft.com/ja-jp/dotnet/maui/user-interface/theming?view=net-maui-9.0

<!-- Colors.xaml -->
<ResourceDictionary>
  <Color x:Key="Primary">#512BD4</Color>
  <Color x:Key="Accent">#D600AA</Color>
</ResourceDictionary>

<!-- Styles.xaml -->
<ResourceDictionary>
  <Style TargetType="Label">
    <Setter Property="TextColor" Value="{DynamicResource Primary}"/>
  </Style>
  <Style TargetType="Label" x:Key="AccentLabel">
    <Setter Property="TextColor" Value="{DynamicResource Accent}"/>
  </Style>
</ResourceDictionary>

<!-- App.xaml にマージ -->
<Application.Resources>
  <ResourceDictionary>
    <ResourceDictionary.MergedDictionaries>
      <ResourceDictionary Source="Resources/Styles/Colors.xaml"/>
      <ResourceDictionary Source="Resources/Styles/Styles.xaml"/>
    </ResourceDictionary.MergedDictionaries>
  </ResourceDictionary>
</Application.Resources>

ラベル全体がPrimaryカラー、キーAccentLabelを指定したラベルがAccentカラーになる。

<Label Text="{Binding Title}" Style="{DynamicResource Key=AccentLabel}" FontAttributes="Bold"/>
<Label Text="{Binding Note}" Grid.Row="1" Opacity="0.8"/>

ポイント: DynamicResource ならテーマ変更時に即反映、StaticResource は起動時に固定される。

変更前 Primaryのみ Accent追加

3. Trigger / VisualState

  • 状態によって見た目を切り替える

DataTrigger例

https://learn.microsoft.com/ja-jp/dotnet/maui/fundamentals/triggers

Done=trueの場合に取り消し線

<Label Text="{Binding Title}" Style="{DynamicResource Key=AccentLabel}" FontAttributes="Bold">
    <Label.Triggers>
        <DataTrigger TargetType="Label" Binding="{Binding Done}" Value="True">
            <Setter Property="TextDecorations" Value="Strikethrough" />
        </DataTrigger>
    </Label.Triggers>
</Label>


VisualState例

  • 複数状態を管理しやすい

https://learn.microsoft.com/ja-jp/dotnet/maui/user-interface/visual-states?view=net-maui-9.0&utm_source=chatgpt.com

選択時の背景色を水色に変更

<Grid Padding="12" ColumnDefinitions="*,Auto">
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="CommonStates">
        <!-- 非選択状態 -->
        <VisualState x:Name="Normal" />
        <!-- 選択状態 -->
        <VisualState x:Name="Selected">
            <VisualState.Setters>
            <Setter Property="BackgroundColor" Value="LightBlue" />
            </VisualState.Setters>
        </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
    <StackLayout Grid.Column="0">
        <Label Text="{Binding Title}" Style="{DynamicResource Key=AccentLabel}" FontAttributes="Bold">
...


4. ControlTemplate

  • デザインパターンを再利用
<ContentPage.Resources>
    <ControlTemplate x:Key="CardTemplate">
        <Frame CornerRadius="8" Margin="4" Padding="12" BackgroundColor="WhiteSmoke">
        <ContentPresenter />
        </Frame>
    </ControlTemplate>
</ContentPage.Resources>
<ContentView ControlTemplate="{StaticResource CardTemplate}">
    <Label Text="ここに中身を書く" />
</ContentView>
<ContentView ControlTemplate="{StaticResource CardTemplate}">
    <Label Text="使いまわし" />
</ContentView>

注意: ContentPresenter を忘れると中身が表示されない。

5. 添付プロパティ(Attached Property)

  • 既存コントロールにプロパティを付け加える
  • 以下の例は必須入力マークをどの入力コントロールにも付けたいとき
Validation.cs
public class Validation
{
    public static readonly BindableProperty IsRequiredProperty =
    BindableProperty.CreateAttached(
        "IsRequired", typeof(bool), typeof(Validation), false,
        propertyChanged: OnIsRequiredChanged);

    public static bool GetIsRequired(BindableObject view)
        => (bool)view.GetValue(IsRequiredProperty);

    public static void SetIsRequired(BindableObject view, bool value)
        => view.SetValue(IsRequiredProperty, value);

    private static void OnIsRequiredChanged(BindableObject bindable, object oldValue, object newValue)
    {
        if (bindable is VisualElement ve && newValue is bool required)
        {
            // 簡易: 背景色で「必須」を表現
            ve.BackgroundColor = required ? Colors.MistyRose : Colors.Transparent;
        }
    }
}
<Entry Placeholder="名前を入力" local:Validation.IsRequired="True"/>
<Editor Placeholder="コメント" local:Validation.IsRequired="False"/>

6. OnPlatform / OnIdiom

  • OS やデバイスごとの見た目調整。

https://learn.microsoft.com/ja-jp/dotnet/maui/platform-integration/customize-ui-appearance?view=net-maui-9.0

<Style TargetType="Button">
  <Setter Property="FontSize">
    <OnPlatform x:TypeArguments="x:Double" Android="16" iOS="14" WinUI="18"/>
  </Setter>
</Style>

便利プロパティ一覧

カテゴリ プロパティ 説明 / 効果
テキスト LineBreakMode="TailTruncation" 長文を「…」で省略
MaxLines="1" 1行でカット(ラベルなど)
CharacterSpacing="2" 文字間隔の調整
MaxLength="50" Entry の最大文字数制限
IsTextPredictionEnabled="False" Entry の予測変換を無効化
Keyboard="Numeric" 数値専用キーボードを表示
レイアウト HorizontalOptions="CenterAndExpand" 中央寄せ+余白均等
VerticalOptions="End" 下寄せ配置
Margin="0" / Padding="0" 余白を削除して詰める
MinimumHeightRequest="44" タッチ領域を確保。小さいボタンのタップ
MaximumWidthRequest="200" 最大幅を制限
ZIndex="10" 重なり順序を指定(前後関係を制御)
視覚効果 Opacity="0.5" 半透明にする
Rotation="45" 回転を与える
Scale="1.2" 拡大縮小
Shadow ドロップシャドウを付ける(MAUI 9.0+)
アクセシビリティ SemanticProperties.Description="説明文" スクリーンリーダー用の説明
AutomationProperties.Name="ボタン説明" アクセシビリティ名
AutomationProperties.HelpText="補足説明" 補助テキスト
画像/メディア Aspect="AspectFit" 画像の比率を保持して収める
Aspect="AspectFill" はみ出しても全体を埋める
IsAnimationPlaying="True"(AnimationView) Lottie などアニメーション再生
入力/操作 IsReadOnly="True" Entry/Editor を読み取り専用に
IsPassword="True" Entry をパスワード入力に
ClearButtonVisibility="WhileEditing" Entry にクリアボタン表示

💡 補足

  • 一部プロパティはプラットフォーム依存
  • バージョンによって追加/制限あり
  • LineBreakMode="TailTruncation"MaxLines="1" → タイトルを一行で省略表示
  • Opacity を頻繁に変えると再描画コストが高くなる → アニメなら FadeTo の方が軽い
  • ZIndex は 同じ親レイアウト内だけ有効。Grid の別セル同士では効かない

Discussion