かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

フォームはラベルの配置場所で使いやすさが全然変わる!ユーザーが利用しやすいフォームを徹底考察をXAMLでやる

coliss.com

こういうフォームって実現大変そう?WinFormsだと死にますね。WPFとかだとテンプレートをいじればOK。

こういう添付プロパティと

public class InfieldLabel
{

    public static string GetContent(DependencyObject obj)
    {
        return (string)obj.GetValue(ContentProperty);
    }

    public static void SetContent(DependencyObject obj, string value)
    {
        obj.SetValue(ContentProperty, value);
    }

    public static readonly DependencyProperty ContentProperty =
        DependencyProperty.RegisterAttached("Content", 
            typeof(string), 
            typeof(InfieldLabel), 
            new PropertyMetadata(null));
}

こういうStyleを定義して

<SolidColorBrush x:Key="TextBox.Static.Border" Color="#FFABAdB3"/>
<SolidColorBrush x:Key="TextBox.MouseOver.Border" Color="#FF7EB4EA"/>
<SolidColorBrush x:Key="TextBox.Focus.Border" Color="#FF569DE5"/>
<Style x:Key="InfieldLabelTextBox" TargetType="{x:Type TextBox}">
    <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
    <Setter Property="BorderBrush" Value="{StaticResource TextBox.Static.Border}"/>
    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
    <Setter Property="HorizontalContentAlignment" Value="Left"/>
    <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
    <Setter Property="AllowDrop" Value="true"/>
    <Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
    <Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TextBox}">
                <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto" />
                            <RowDefinition />
                        </Grid.RowDefinitions>
                        <Label Content="{TemplateBinding local:InfieldLabel.Content}" />
                        <ScrollViewer x:Name="PART_ContentHost" Grid.Row="1" Margin="5" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
                    </Grid>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsEnabled" Value="false">
                        <Setter Property="Opacity" TargetName="border" Value="0.56"/>
                    </Trigger>
                    <Trigger Property="IsMouseOver" Value="true">
                        <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource TextBox.MouseOver.Border}"/>
                    </Trigger>
                    <Trigger Property="IsKeyboardFocused" Value="true">
                        <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource TextBox.Focus.Border}"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Style.Triggers>
        <MultiTrigger>
            <MultiTrigger.Conditions>
                <Condition Property="IsInactiveSelectionHighlightEnabled" Value="true"/>
                <Condition Property="IsSelectionActive" Value="false"/>
            </MultiTrigger.Conditions>
            <Setter Property="SelectionBrush" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}"/>
        </MultiTrigger>
    </Style.Triggers>
</Style>

こんな感じで使えます。

<TextBox Style="{StaticResource InfieldLabelTextBox}" 
         local:InfieldLabel.Content="名前" 
         Margin="5"/>
<TextBox Style="{StaticResource InfieldLabelTextBox}" 
         local:InfieldLabel.Content="年齢" 
         Margin="5"/>
<TextBox Style="{StaticResource InfieldLabelTextBox}" 
         local:InfieldLabel.Content="住所" 
         Margin="5"/>