2019年5月12日日曜日

VB Form 等の縦横比を固定 WPF 編

何か、ややこしいタイトルになって仕舞いましたが ... 。
WPF の場合も、Form 同様に ... 。
待ったぁ~!。
そうは問屋が卸しません!。


WPF に於いて、 API を直接叩くには、 おまじない! が必要です。
先に投稿 した様に、Windows API を叩く事で、
画面のちらつきが無く、描画が出来る訳ですが、
そのまま、Form でのテクニックを WPF に持ち込んでも、動かない様です。

以下のサイトに簡潔に説明されていました。
WPF のウィンドウ(その1) by ダッチ さま
http://blogs.wankuma.com/youryella/archive/2009/10/20/182272.aspx

コードをお借りして、引用します。  著作権:ダッチ さま

Imports System.Windows.Interop

Private Class Window1
    Private Sub Window1_SourceInitialized(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.SourceInitialized
        Dim wih As New WindowInteropHelper(Me)
        Dim hs As HwndSource = HwndSource.FromHwnd(wih.Handle)
        hs.AddHook(AddressOf WndProc)
    End Sub
    Private Function WndProc(ByVal hwnd As IntPtr, ByVal msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr, ByRef handled As Boolean) As IntPtr
        ' WndProc と同じように処理できます。
        Return IntPtr.Zero
    End Function
End Class

WPF には、WndProc メソッドが無い のだそうです。
ですから、上記の様に、書き足す必要があるのですね。


Form と較べて、条件分岐は単純化が可能です。
冒頭に条件判断部分を入れてしまえば、簡潔に書けますね。



後日、 Sample Code  挿入予定。. *1.

Window1 の xaml に CheckBox をひとつ用意し、CheckBox1 と命名します。
Code (Window1.xaml.vb) はこちら。  縦横比 4:3 (横長) で固定可能の例。

 Imports System.Windows.Interop

Public Class Window1

    Private Sub Window1_SourceInitialized(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.SourceInitialized
        Dim wih As New WindowInteropHelper(Me)
        Dim hs As HwndSource = HwndSource.FromHwnd(wih.Handle)
        hs.AddHook(AddressOf WndProc)
    End Sub

    ' For Fixed WH_Ratio
    Private fixedRate As Double = (CType(4 / 3, Double))
    Private WM_SIZING As Integer = 532
    Private WMSZ_LEFT As Integer = 1
    Private WMSZ_RIGHT As Integer = 2
    Private WMSZ_TOP As Integer = 3
    Private WMSZ_TOPLEFT As Integer = 4
    Private WMSZ_TOPRIGHT As Integer = 5
    Private WMSZ_BOTTOM As Integer = 6
    Private WMSZ_BOTTOMLEFT As Integer = 7
    Private WMSZ_BOTTOMRIGHT As Integer = 8

    Structure RECT
        Public left As Integer
        Public top As Integer
        Public right As Integer
        Public bottom As Integer
    End Structure

    Private Function WndProc(ByVal hwnd As IntPtr,
                             ByVal msg As Integer,
                             ByVal wParam As IntPtr,
                             ByVal lParam As IntPtr,
                             ByRef handled As Boolean) As IntPtr
        ' Like Form's WndProc
        If msg = WM_SIZING Then
            If Me.CheckBox1.IsChecked Then

                Dim r = CType(System.Runtime.InteropServices.Marshal.PtrToStructure(lParam, GetType(RECT)), RECT)      
                Dim w = r.right - r.left
                Dim h = r.bottom - r.top
                Dim dw As Integer = (CType(((h * fixedRate) _
                            + 0.5), Integer) - w)
                Dim dh As Integer = (CType(((w / fixedRate) _
                            + 0.5), Integer) - h)
                Select Case wParam.ToInt32
                    Case WMSZ_TOP, WMSZ_BOTTOM
                        r.right = (r.right + dw)
                    Case WMSZ_LEFT, WMSZ_RIGHT
                        r.bottom = (r.bottom + dh)
                    Case WMSZ_TOPLEFT
                        If (dw > 0) Then
                            r.left = (r.left - dw)
                        Else
                            r.top = (r.top - dh)
                        End If

                    Case WMSZ_TOPRIGHT
                        If (dw > 0) Then
                            r.right = (r.right + dw)
                        Else
                            r.top = (r.top - dh)
                        End If

                    Case WMSZ_BOTTOMLEFT
                        If (dw > 0) Then
                            r.left = (r.left - dw)
                        Else
                            r.bottom = (r.bottom + dh)
                        End If

                    Case WMSZ_BOTTOMRIGHT
                        If (dw > 0) Then
                            r.right = (r.right + dw)
                        Else
                            r.bottom = (r.bottom + dh)
                        End If

                End Select

                System.Runtime.InteropServices.Marshal.StructureToPtr(r, lParam, False)

            Else
                'MyBase.WndProc(m)
            End If
        End If
        Return IntPtr.Zero
    End Function
End Class



これで、何とか、目的達成! です。



[2019/05/14] Sample Code 挿入

0 件のコメント:

コメントを投稿