🎨
.NET MAUI スタイリングメモ
はじめに
.NET MAUI アプリ開発でUIを作るときのメモ。
1. 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
- 見た目を共通化・テーマ対応
<!-- 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例
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例
- 複数状態を管理しやすい
選択時の背景色を水色に変更
<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 やデバイスごとの見た目調整。
<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