スクリーンのスケーリング時に非表示のスピンボタンの一部が表示される

文書番号 : 41749     文書種別 : 不具合     登録日 : 2018/04/12     最終更新日 : 2018/06/27
文書を印刷する
対象製品
MultiRow for Windows Forms 10.0J
状況
修正済み
詳細
■現象
ディスプレイのDPI(スケーリング)を125%にした時に、数値スピンボタンを非表示にしたNumericUpDownCell の編集時にスピンボタンの一部が右側に表示されます。(クリックすると値が増減します)

■再現手順
1. MultiRowをフォームに配置後、NumericUpDownCell を以下のように設定します。
ShowSpinButton = NotShown
ShowSpinButtonInEditState = false

2. 画面の設定でディスプレイのDPI(スケーリング)を125%に設定します。(一旦サインアウトしないと反映されません)
3. 1.のコードを実行し、NumericUpDownCell のセルを編集状態にすると現象が発生します。
回避方法
この問題はService Pack 2(v10.0.4002.2012)で修正されました。
不具合を修正した最新のサービスパックは、アップデートページ からダウンロードできます。

Service Pack 2 未適用のときは以下の回避方法をご検討ください。

NumericUpDownCell はEditコントロールを使用し数値スピンボタン部分を隠しています。GetEditingControlBoundsをオーバーライドし、Editコントロールの境界を調整することで現象を回避できます。

◎サンプルコード(C#)
Form1.Designer.cs

using GrapeCity.Win.MultiRow;
using System;
using System.Configuration;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace MultiRowSampleProject
{
  partial class Form1
  {
    /// <summary>
    /// 必要なデザイナー変数です。
    /// </summary>
    private System.ComponentModel.IContainer components = null;

    /// <summary>
    /// 使用中のリソースをすべてクリーンアップします。
    /// </summary>
    /// <param name="disposing">マネージ リソースを破棄する場合は true を指定し、その他の場合は false を指定します。</param>
    protected override void Dispose(bool disposing)
    {
      if (disposing && (components != null))
      {
        components.Dispose();
      }
      base.Dispose(disposing);
    }

    #region Windows フォーム デザイナーで生成されたコード

    /// <summary>
    /// デザイナー サポートに必要なメソッドです。このメソッドの内容を
    /// コード エディターで変更しないでください。
    /// </summary>
    private void InitializeComponent()
    {
      this.gcMultiRow1 = new GrapeCity.Win.MultiRow.GcMultiRow();
      this.template11 = new MultiRowSampleProject.Template1();
      ((System.ComponentModel.ISupportInitialize)(this.gcMultiRow1)).BeginInit();
      this.SuspendLayout();
      //
      // gcMultiRow1
      //
      this.gcMultiRow1.Dock = System.Windows.Forms.DockStyle.Fill;
      this.gcMultiRow1.Location = new System.Drawing.Point(0, 0);
      this.gcMultiRow1.Name = "gcMultiRow1";
      this.gcMultiRow1.Size = new System.Drawing.Size(302, 193);
      this.gcMultiRow1.TabIndex = 0;
      this.gcMultiRow1.Template = this.template11;
      this.gcMultiRow1.Text = "gcMultiRow1";
      //
      // Form1
      //
      this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 17F);
      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
      this.ClientSize = new System.Drawing.Size(302, 193);
      this.Controls.Add(this.gcMultiRow1);
      this.Font = new System.Drawing.Font("MS ゴシック", 10F);
      this.Name = "Form1";
      this.Text = "Form1";
      ((System.ComponentModel.ISupportInitialize)(this.gcMultiRow1)).EndInit();
      this.ResumeLayout(false);

    }

    #endregion

    private GrapeCity.Win.MultiRow.GcMultiRow gcMultiRow1;
    private Template1 template11;
  }

  public class CustomNumericUpDownCell : NumericUpDownCell
  {
    protected override Rectangle GetEditingControlBounds(Rectangle cellBounds, int rowIndex)
    {
      var rect = base.GetEditingControlBounds(cellBounds, rowIndex);
      if (!ShowSpinButtonInEditState)
      {
        var spinWidth = 16;
        var field = typeof(UpDownBase).GetField("defaultButtonsWidth", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
        if (field != null)
        {
          spinWidth = (int)field.GetValue(null);
        }
        var offset = CustomDpiHelper.ScaleX(spinWidth) - spinWidth;
        rect.Width += offset;
      }
      return rect;
    }
  }

  public static class CustomDpiHelper
  {
    private static float _logicDpiX;
    private static float _deviceDpiX;

    static CustomDpiHelper()
    {
      _logicDpiX = 96;
      _deviceDpiX = 96;
      try
      {
        if (string.Equals(ConfigurationManager.AppSettings.Get("EnableWindowsFormsHighDpiAutoResizing"), "true", StringComparison.InvariantCultureIgnoreCase))
        {

          IntPtr hdc = UnsafeNativeMethods.GetDC(IntPtr.Zero);
          if (hdc != IntPtr.Zero)
          {
            _deviceDpiX = UnsafeNativeMethods.GetDeviceCaps(hdc, 88);
            UnsafeNativeMethods.ReleaseDC(IntPtr.Zero, hdc);
          }
        }
      }
      catch
      {
        return;
      }
    }

    public static int ScaleX(int x)
    {
      return (int)Math.Round(_deviceDpiX / _logicDpiX * x, MidpointRounding.AwayFromZero);
    }
  }

  [System.Security.SuppressUnmanagedCodeSecurity()]
  internal static partial class UnsafeNativeMethods
  {
    [DllImport("user32.dll")]
    public static extern System.IntPtr GetDC(System.IntPtr hWnd);

    [DllImport("gdi32.dll")]
    public static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
    [DllImport("user32.dll")]
    public static extern int ReleaseDC(System.IntPtr hWnd, System.IntPtr hDC);
  }
}