TabControl上にGcSpreadGridを配置して非表示の状態で検証を実行すると、検証エラーが正しく表示されない場合がある

文書番号 : 86154     文書種別 : 不具合     登録日 : 2020/10/29     最終更新日 : 2020/10/29
文書を印刷する
対象製品
SPREAD for WPF 3.0J
状況
回避方法あり
詳細
TabControlコントロール上のTabItemにGcSpreadGridコントロールを配置し、GcSpreadGridが配置されたTabItemが非表示の状態で検証処理を実行すると、検証エラー(赤い三角のアイコン)が正しく表示されません。

なお、コントロールを配置したTabItemを一度表示させると本現象は発生しません。
回避方法
検証処理を実行する際に、一時的にGcSpreadGridを配置したタブをアクティブにします。また、その際に発生するウィンドウの描画のちらつきを防止する処理を行います。

以下はボタンのクリックイベントで検証処理を行う場合の例です。

◎サンプルコード(VB)
Class MainWindow
  Private Async Sub button_Click(sender As Object, e As RoutedEventArgs) Handles button.Click
    ' 検証処理の際に一時的に2つめのタブをアクティブにする
    Await Threading.Dispatcher.Yield
    Using New ReduceBlinkHelper(Me, BlinkBuffer)
      tabControl.SelectedIndex = 1
      Await Threading.Dispatcher.Yield
      ' 検証処理
      GcSpreadGrid1.ValidateAll()
      tabControl.SelectedIndex = 0
    End Using
  End Sub
End Class

' 描画のちらつきを防止する処理
Public Class ReduceBlinkHelper
  Implements IDisposable

  Private ReadOnly _bufferImage As Image
  Sub New(window As Window, bufferImage As Image)
    _bufferImage = bufferImage
    BeginReduceBlink(window)
  End Sub

  Private Sub BeginReduceBlink(window As Window)
    Dim beforeBlink = CaptureImage(window)
    _bufferImage.Source = beforeBlink
    _bufferImage.Visibility = Visibility.Visible
  End Sub

  Private Sub EndReduceBlink()
    _bufferImage.Source = Nothing
    _bufferImage.Visibility = Visibility.Collapsed
  End Sub

  Private Shared Function CaptureImage(window As Window) As ImageSource

    Dim dpiScale = VisualTreeHelper.GetDpi(window)
    Dim helper As New WindowInteropHelper(window)
    Dim hWnd = helper.Handle

    Dim clientPos As New System.Drawing.Point
    ClientToScreen(hWnd, clientPos)

    Dim clientRect As New Int32Rect
    GetClientRect(hWnd, clientRect)

    Dim windowRect As New Int32Rect
    GetWindowRect(hWnd, windowRect)

    clientRect.X = clientPos.X - windowRect.X
    clientRect.Y = clientPos.Y - windowRect.Y

    Using bitmap As New System.Drawing.Bitmap(clientRect.Width, clientRect.Height, PixelFormat.Format32bppArgb)
      bitmap.SetResolution(dpiScale.PixelsPerInchX, dpiScale.PixelsPerInchY)
      Using imageGraphics = System.Drawing.Graphics.FromImage(bitmap)
        Dim dc = imageGraphics.GetHdc()
        Dim windowDC = GetWindowDC(hWnd)

        BitBlt(dc, 0, 0, clientRect.Width, clientRect.Height, windowDC, clientRect.X, clientRect.Y, SRCCOPY)

        imageGraphics.ReleaseHdc(dc)
        ReleaseDC(hWnd, windowDC)
      End Using

      Return ImageSourceFromBitmap(bitmap)
    End Using
  End Function

  Private Shared Function ImageSourceFromBitmap(bmp As System.Drawing.Bitmap) As ImageSource
    Dim ms As New MemoryStream
    bmp.Save(ms, ImageFormat.Tiff)
    ms.Position = 0
    Dim tifDecoder As New TiffBitmapDecoder(ms, BitmapCreateOptions.None, BitmapCacheOption.None)
    Return tifDecoder.Frames.First
  End Function

#Region "  PInvoke"

  Private Declare Function ClientToScreen Lib "user32.dll" (hWnd As IntPtr, ByRef point As System.Drawing.Point) As Boolean
  Private Declare Function GetClientRect Lib "user32.dll" (hWnd As IntPtr, ByRef rect As Int32Rect) As Boolean
  Private Declare Function GetWindowRect Lib "user32.dll" (hWnd As IntPtr, ByRef rect As Int32Rect) As Boolean
  Private Declare Function DeleteObject Lib "gdi32.dll" (hObject As IntPtr) As Boolean
  Private Declare Function BitBlt Lib "gdi32.dll" (
    hdcDest As IntPtr, xDest As Integer, yDest As Integer,
    wDest As Integer, hDest As Integer, hdcSource As IntPtr,
    xSrc As Integer, ySrc As Integer, rop As Integer) As Boolean
  Private Declare Function GetWindowDC Lib "user32.dll" (ptr As IntPtr) As IntPtr
  Private Declare Function ReleaseDC Lib "user32.dll" (hWnd As IntPtr, hDc As IntPtr) As Boolean
  Private Const SRCCOPY = &HCC0020
#End Region

#Region "  Implement IDisposable"
  Private disposedValue As Boolean

  Protected Overridable Sub Dispose(disposing As Boolean)
    If Not disposedValue Then
      If disposing Then
        EndReduceBlink()
      End If

      disposedValue = True
    End If
  End Sub

  Public Sub Dispose() Implements IDisposable.Dispose
    Dispose(disposing:=True)
    GC.SuppressFinalize(Me)
  End Sub
#End Region
End Class
キーワード
GcSpreadGrid