💴

C# - ComboBox - 右詰め 3桁カンマ区切り

に公開

はじめに

ComboBox、数値の場合には右詰め表示としたいですよね。
本記事では、3桁カンマ区切り数値で右詰めとする手法を記載します。

テスト環境

ここに記載した情報/ソースコードは、Visual Studio Community 2022 を利用した下記プロジェクトで生成したモジュールを Windows 11 24H2 で動作確認しています。

  • Windows Forms - .NET Framework 4.8
  • Windows Forms - .NET 8
  • WPF - .NET Framework 4.8
  • WPF - .NET 8

Windows Forms

https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.forms.combobox

ComboBox.DropDownStyle で DropDownList と DropDown の切り替えます。

c# - Align Text in Combobox - Stack Overflow

Windows Forms の場合、ComboBox.DrawMode = DrawMode.OwnerDrawFixed として、DrawItem イベントハンドラで、StringFormat を用いて右詰め描画する必要があります。

Form1.cs
public partial class Form1 : Form
{
  public Form1()
  {
    InitializeComponent();

    // デザイナで ComboBox comboBox1 を配置
    comboBox1.DrawMode = DrawMode.OwnerDrawFixed; // カスタム描画モード
    comboBox1.DropDownStyle = ComboBoxStyle.DropDownList;
    comboBox1.Items.AddRange(new object[]
    {
      1000000, 300000000, 3333, -10000, 123456789
    });
    // comboBox1.FormatString = "N0";  // DrawMode.OwnerDrawFixed 時は無効
    comboBox1.DrawItem += comboBox_DrawItem;
  }
  // .NET Framework 時 object? の ? 不要
  private void comboBox_DrawItem(object? sender, DrawItemEventArgs e)
  {
    if (sender is ComboBox cbox)
    {
      if (e.Font != null && e.Index >= 0)
      {
        // 背景描画
        e.DrawBackground();
        // 数値の場合 3桁カンマ区切り反映
        string text;
        var obj = cbox.Items[e.Index];
        if (obj is int number)
        {
          text = number.ToString("N0");
        }
        else
        {
          text = obj?.ToString() ?? string.Empty;
        }
        // テキスト描画
        using (Brush textBrush = new SolidBrush(e.ForeColor))
        using (var textFormat = new StringFormat())
        {
          textFormat.Alignment = StringAlignment.Far;        // 水平方向:右寄せ
          textFormat.LineAlignment = StringAlignment.Center; // 垂直方向:中央寄せ
          e.Graphics.DrawString(text, e.Font, textBrush, e.Bounds, textFormat);
        }
        // フォーカス矩形描画
        e.DrawFocusRectangle();
      }
    }
  }
}

ComboBox.RightToLeft = RightToLeft.Yes で右詰め、Leaveイベントで 3桁カンマ区切りとすることができますが、一覧表示リスト展開ボタンが左配置となってしまいます。

Form1.cs
public Form1()
{
  InitializeComponent();

  // デザイナで ComboBox comboBox1 を配置
  comboBox1.DrawMode = DrawMode.OwnerDrawFixed;     // カスタム描画モード
  comboBox1.DropDownStyle = ComboBoxStyle.DropDown; // TODO:DropDownに変更
  comboBox1.Items.AddRange(new object[]
  {
    1000000, 300000000, 3333, -10000, 123456789
  });
  // comboBox1.FormatString = "N0";  // DrawMode.OwnerDrawFixed 時は無効
  comboBox1.DrawItem += comboBox_DrawItem;

  // TODO:下記処理を追加
  comboBox1.RightToLeft = RightToLeft.Yes;
  comboBox1.Leave += ComboBox_Leave;
}
<中略>
// .NET Framework 時 object? の ? 不要
private void ComboBox_Leave(object? sender, EventArgs e)
{
  if (sender is ComboBox cbox && !string.IsNullOrEmpty(cbox.Text)
   && Int64.TryParse(cbox.Text.Trim().Replace(",", ""), out Int64 value))
  {
    cbox.Text = value.ToString("N0");
  }
}

一覧表示リスト展開ボタン左配置は、不自然ですよね、、、
右配置のまま、編集、もしくは、選択した値を右詰めとするには、ComboBox 編集領域(TextBox)に対する操作が必要となります。
Leave、HandleCreated などのイベントで、ComboBox.Controls[] としてアクセス可能かを確認しましたが、期待通りの動作は得られませんでした。
下記情報通りに、カスタムコントール化が必要ということですね。(コード提示は割愛します)

WPF

https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.controls.combobox

Windows Forms の ComboBox では、ComboBox.DropDownStyle で DropDownList と DropDown を切り替えていましたが、WPF では IsEditable を False(DropDownList)True(DropDown)で切り替えます。

右寄せは、ComboBox.HorizontalContentAlignment(選択した値)と <ComboBox.ItemTemplate>(選択値) で行います。
MVVM モデルは割愛して、単純にコードビハインドでデータを指定する方法を記載します。

MainWindow.xaml
<Window x:Class="WpfApp1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WpfApp1"
    mc:Ignorable="d"
    Title="MainWindow" Height="200" Width="400">
  <Grid Margin="10" >
    <Grid.RowDefinitions>
      <RowDefinition Height="*" />
      <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <!-- SelectedItem に対する指定:HorizontalContentAlignment -->
    <ComboBox x:Name="comboBox1" Grid.Row="0" Width="125"
              IsEditable="False" IsReadOnly="False"
              HorizontalAlignment="Left" VerticalAlignment="Top"
              HorizontalContentAlignment="Right"
              Loaded="comboBox_Loaded">
      <ComboBox.ItemTemplate>
        <DataTemplate>
          <TextBlock Text="{Binding StringFormat={}{0:N0}}" HorizontalAlignment="Right"/>
        </DataTemplate>
      </ComboBox.ItemTemplate>
    </ComboBox>
    <!-- ComboBox の LostFocus 挙動確認用にコントール配置 -->
    <Button x:Name="button1" Grid.Row="1"
            Width="125" Height="20" Content="ボタン"
            HorizontalAlignment="Center" VerticalAlignment="Bottom"/>
  </Grid>
</Window>
MainWindow.xaml.cs
// .NET Framework 時は object? の ? 不要
private void comboBox_Loaded(object? sender, RoutedEventArgs e)
{
  if (sender is ComboBox cbox)
  {
    cbox.ItemsSource = new List<int> { 1000000, 300000000, 3333, -10000, 123456789 };
  }
}

DropDown の場合、前述コードに対して LostFocus で 3桁カンマ区切り整形の処理を追加します。

MainWindow.xaml
<Window x:Class="WpfApp1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WpfApp1"
    mc:Ignorable="d"
    Title="MainWindow" Height="200" Width="400">
  <Grid Margin="10" >
    <Grid.RowDefinitions>
      <RowDefinition Height="*" />
      <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <!-- SelectedItem に対する指定:HorizontalContentAlignment -->
    <ComboBox x:Name="comboBox1" Grid.Row="0" Width="125"
              IsEditable="False" IsReadOnly="False"
              HorizontalAlignment="Left" VerticalAlignment="Top"
              HorizontalContentAlignment="Right"
              Loaded="comboBox_Loaded" LostFocus="comboBox_LostFocus">
      <ComboBox.ItemTemplate>
        <DataTemplate>
          <TextBlock Text="{Binding StringFormat={}{0:N0}}" HorizontalAlignment="Right"/>
        </DataTemplate>
      </ComboBox.ItemTemplate>
    </ComboBox>
    <!-- ComboBox の LostFocus 挙動確認用にコントール配置 -->
    <Button x:Name="button1" Grid.Row="1"
            Width="125" Height="20" Content="ボタン"
            HorizontalAlignment="Center" VerticalAlignment="Bottom"/>
  </Grid>
</Window>
MainWindow.xaml.cs
// .NET Framework 時は object? の ? 不要
private void comboBox_Loaded(object? sender, RoutedEventArgs e)
{
  if (sender is ComboBox cbox)
  {
    cbox.ItemsSource = new List<int> { 1000000, 300000000, 3333, -10000, 123456789 };
  }
}
// .NET Framework 時は object? の ? 不要
private void comboBox_LostFocus(object? sender, RoutedEventArgs e)
{
  if (sender is ComboBox cbox && !string.IsNullOrEmpty(cbox.Text)
   && Int64.TryParse(cbox.Text.Trim().Replace(",", ""), out Int64 value))
  {
    cbox.Text = value.ToString("N0"); // 3桁カンマ区切り
  }
}

出典

本記事は、2025/07/01 Qiita 投稿記事の転載です。

C# - ComboBox - 右詰め 3桁カンマ区切り

Discussion