2008年6月24日

 だんだん暑くなってきました。そんなわけで見た目に涼しいグラスフレームのコードを書いてみたよ。

 Vistaの特長である(でもHome Basicは未対応)グラスフレーム(ブラーともいう)についてです。通常はウィンドウを作成するとウィンドウ枠内は不透明になりますが、IEの上部やMedia Playerの下部なんかは通常のウィンドウより透明の領域が多いですよね(当然ながらVistaの話し)。このような透明領域を増やす、クライアント領域の拡張はDesktop Window Manager (DWM)のAPIを呼び出すことで簡単にできます。そのことが日本語でMSDNにもろ書いてます。

WPF アプリケーションへのグラス フレームの拡張

 記事はC#だったのでVBのコードを置いておきますね。XAMLは記事と同じです。

Imports System.Runtime.InteropServices

Public Class NonClientRegionAPI
    <StructLayout(LayoutKind.Sequential)> _
    Structure MARGINS
        Public cxLeftWidth As Integer
        Public cxRightWidth As Integer
        Public cyTopHeight As Integer
        Public cyBottomHeight As Integer
    End Structure

    <DllImport("DwmApi.dll")> _
    Public Shared Function DwmExtendFrameIntoClientArea(ByVal hwnd As IntPtr, ByRef pMarInset As MARGINS) As Integer
    End Function
End Class

Private Sub OnLoaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
    Try
        Dim mainWindowPtr = New WindowInteropHelper(Me).Handle
        Dim mainWindowSrc = HwndSource.FromHwnd(mainWindowPtr)
        mainWindowSrc.CompositionTarget.BackgroundColor = Color.FromArgb(0, 0, 0, 0)

        ' Get System Dpi
        Dim desktop = System.Drawing.Graphics.FromHwnd(mainWindowPtr)
        Dim DesktopDpiX = desktop.DpiX
        Dim DesktopDpiY = desktop.DpiY

        ' Set Margins
        Dim margins = New NonClientRegionAPI.MARGINS

        ' Extend glass frame into client area
        ' Note that the default desktop Dpi is 96dpi. The  margins are
        ' adjusted for the system Dpi.
        margins.cxLeftWidth = CInt((5 * (DesktopDpiX / 96)))
        margins.cxRightWidth = CInt(5 * (DesktopDpiX / 96))
        margins.cyTopHeight = CInt((CInt(topBar.ActualHeight) + 5) * (DesktopDpiX / 96))
        margins.cyBottomHeight = CInt(5 * (DesktopDpiX / 96))

        Dim hr = NonClientRegionAPI.DwmExtendFrameIntoClientArea(mainWindowSrc.Handle, margins)
        If hr < 0 Then
            ' DwmExtendFrameIntoClientArea Failed
        End If

    Catch ex As DllNotFoundException
        Application.Current.MainWindow.Background = Brushes.White
    End Try
End Sub

 marginsに透明にする部分の大きさ上下左右それぞれに指定してます。一度設定してしまえばウィンドウの大きさが変更されたとしても問題ありません。ただ、実際にWPFアプリケーションで実行してみて気になったのは、ウィンドウの拡大時に一瞬 不透明の部分が黒く見えてしまって見栄えが気になる。ドラッグの操作によりウィンドウ幅が変わるけど、ウィンドウ上のコントロールが変更に少し遅れて追従してるのでコントロールの後ろにあるウィンドウ自身が見えるのです。根本的解決ではありませんが、ウィンドウすべての領域を透明に指定することで黒く見える領域(不透明領域)がなくなるのでマシな感じです。すべてを透明に指定するにはmarginsの各値を-1にするとできます。 

 MISAOに適用してみた結果。

image

 ウィンドウを最大化すると不透明になり、通常は黒っぽい色になります。なので上のように黒い文字があると見えづらくなるので これはダメですね。

posted @ 23:05 | Feedback (294)