1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Posted at

はじめに

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

記載したソースコードは .NET 8 ベースとしています。
.NET Framework 4.8 の場合は、コメントで記載している null 許容参照型の明示 ? を削除してください。

Visual Studio 2022 - .NET Framework 4.8 は、C# 7.3 が既定です。
このため、サンプルコードは、C# 7.3 機能範囲で記述しています。

Windows Forms

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

DropDownList

WindowsForms-01.png

c# - Align Text in Combobox - Stack Overflow

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

ComboBox.DrawMode = DrawMode.OwnerDrawFixed の場合、ComboBox.FormatString を指定しても反映されないので、DrawItem イベントハンドラで、3桁カンマ区切りの処理も行います。

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();
      }
    }
  }
}

DropDown

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

WindowsForms-02.png

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

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

DropDownList

WPF-01.png

右寄せは、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

WPF-02.png

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桁カンマ区切り
  }
}
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?