none
タイトルバーに喰い込むようにコントロールを配置したい RRS feed

  • 質問

  • [Visual Studio 2008 RTM, WindowsVista Business]

     

    [XAMLコード]

    <Window
     x:Class="WpfApplication1.Window1"
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     Title="Window1" Height="300" Width="300"
     AllowsTransparency="True" Background="Transparent" WindowStyle="None">
     <Border BorderBrush="#FF404040" BorderThickness="1" CornerRadius="5">
      <Border BorderBrush="#FFFFFFFF" BorderThickness="1" CornerRadius="5">
      </Border>
     </Border>
    </Window>

     

    [C#コード]

    using System;
    using System.Runtime.InteropServices;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Interop;
    using System.Windows.Media;

    namespace WpfApplication1
    {
     public partial class Window1 : Window
     {
      public Window1()
      {
       InitializeComponent();

      }

      protected override void OnSourceInitialized(EventArgs e)
      {
       base.OnSourceInitialized(e);

       GlassExtender.ExtendGlassFrame(this, new Thickness(-1));
      }
     }

     public static class GlassExtender
     {
      [DllImport("dwmapi.dll", PreserveSig = false)]
      static extern void DwmExtendFrameIntoClientArea(IntPtr hwnd, ref MARGINS MARGINS);

      [DllImport("dwmapi.dll", PreserveSig = false)]
      static extern bool DwmIsCompositionEnabled();

      struct MARGINS
      {
       public int Left;
       public int Right;
       public int Top;
       public int Bottom;
       public MARGINS(Thickness t)
       {
        Left = (int)t.Left;
        Right = (int)t.Right;
        Top = (int)t.Top;
        Bottom = (int)t.Bottom;
       }
      }

      public static bool ExtendGlassFrame(Window target, Thickness t)
      {
       if (!DwmIsCompositionEnabled()) return false;

       IntPtr handle = new WindowInteropHelper(target).Handle;
       if (handle == IntPtr.Zero) throw new InvalidOperationException("このウィンドウはGlass機能を使用できません。");

       target.Background = Brushes.Transparent;
       HwndSource.FromHwnd(handle).CompositionTarget.BackgroundColor = Colors.Transparent;

       MARGINS margins = new MARGINS(t);
       DwmExtendFrameIntoClientArea(handle, ref margins);

       return true;
      }
     }
    }

     

     

    上記ソースは、WindowStyleがNoneのWindowにDwmExtendFrameIntoClientAreaでVistaのAero効果を付けているのですが、

    透明なWindowが表示されてしまいます。

     

    これは、WPFの仕様なのですか?

    よろしくお願いします。

    2007年12月28日 6:57

回答

  • WPFの描画自体が、ウィンドウのクライアント領域を出る事が出来ない様な

    ので、簡単には(標準では)出来ないと思います。

     

    ある程度簡単にと言う事であれば、Window.WindowStyleにNoneを指定して

    おいて、自作のタイトルバーを配置しておくと言う方法になるかと思います。

     

    難しい方法になると、ウィンドウプロシージャをフックして、WM_NCPAINT時

    に独自描画でコントロール部分を描画してあげる方法になるんじゃないかと…。

    (私には、独自描画でWPFのコントロールを描画する方法は解りません。)

    2008年1月8日 2:32

すべての返信

  • AllowsTransparency が True になっているのが原因ではないでしょうか?

    DWMのグラス効果はレイヤードウィンドウには適用できないのかもしれません。詳しく調べていないので正しいのかわかりませんが……。

    2007年12月31日 7:44
  • しばやん様、ご回答ありがとうございます。

    返信が遅くなりまして、申し訳ございません。

     

    やはり、AllowsTransparency = True が原因ですね。

     

     

    では、質問の内容を変えさせていただきます。

    WPFウィンドウにエクスプローラの検索バーのようなコントロールをタイトルバーに喰い込むように配置したいのですが、どのようにすれば良いのでしょうか。

     

    理想は、Office2007のクイックアクセスツールバーのような感じなのですが…

     

    使うAPIやヒントだけでもよろしくお願いします。

    2008年1月7日 7:42
  • 以下のページ

    Custom Window Control - GlassWindow - Source Code

    http://pavanpodila.spaces.live.com/blog/cns!9C9E888164859398!345.entry

    が,参考になりそうですけどね。

    (Feel free to use the code as you wish. と書かれていますし)

     

    Window から派生させた (自作の) GlassWindow クラスに,

    MacOS X スタイルのほうでは,独自に ControlTemplate をあてています。

    GlassWindow の AttachToVisualTree() と連携しています。

    (TemplatePart属性で紐付けしています)

     

    追加したいものを加えればやれるんじゃないかな。

    2008年1月7日 9:11
  •  yayadon さんからの引用

    以下のページ

    Custom Window Control - GlassWindow - Source Code

    http://pavanpodila.spaces.live.com/blog/cns!9C9E888164859398!345.entry

    が,参考になりそうですけどね。

    (Feel free to use the code as you wish. と書かれていますし)

     

    Window から派生させた (自作の) GlassWindow クラスに,

    MacOS X スタイルのほうでは,独自に ControlTemplate をあてています。

    GlassWindow の AttachToVisualTree() と連携しています。

    (TemplatePart属性で紐付けしています)

     

    追加したいものを加えればやれるんじゃないかな。

     

     

    yayadon様、ご回答ありがとうございます。

    ご呈示いただいたサンプルソースは以前に拝見しています。

    ControlTemplateやTemplatePartの使用方法がわかり易いのですが、私がしたいモノと若干違います。

     

    このサンプルソースでは、AllowsTransparencyをTrueにしているためDWMでGlass効果にできません。

    実行時に非クライアント領域にクライアント領域のコントロールの一部(検索バーコントロールなど)を喰い込ませて、且つDWMでGlass効果を有効にしたWPF Windowっていうのは、どのようにすれば良いのでしょうか。

     

    (デザイン時)                          (実行時)

    ┌────────┐            ┌────────┐

    │        │← 非クライアント領域 →│   ┌───┐│

    ├───┬───┬┤            ├───┴───┴┤

    │   └───┘│            │        │

    │        │            │        │

    │        │← クライアント領域 →│        │

    │        │            │        │

    └────────┘            └────────┘

     

    質問内容に不備があり、申し訳ございませんが、もう一度よろしくお願いします。

     

    2008年1月7日 11:26
  • WPFの描画自体が、ウィンドウのクライアント領域を出る事が出来ない様な

    ので、簡単には(標準では)出来ないと思います。

     

    ある程度簡単にと言う事であれば、Window.WindowStyleにNoneを指定して

    おいて、自作のタイトルバーを配置しておくと言う方法になるかと思います。

     

    難しい方法になると、ウィンドウプロシージャをフックして、WM_NCPAINT時

    に独自描画でコントロール部分を描画してあげる方法になるんじゃないかと…。

    (私には、独自描画でWPFのコントロールを描画する方法は解りません。)

    2008年1月8日 2:32
  •  

    FC-Shiro様、ご回答ありがとうございます。

     

    今回の案件が、UIがWPFでGlass有りなので、WindowStyle=Noneが使えません。

    難しいとは思いますが、ウィンドウプロシージャをフックする方法で試してみたいと思います。

     

    ありがとうございました。

     

    2008年1月8日 3:18
  •  tom_tom さんからの引用

    今回の案件が、UIがWPFでGlass有りなので、WindowStyle=Noneが使えません。

     

    WindowStyle=NoneだとGlassが出来ないなんて事はないと思うんですけど ?

    2008年1月9日 5:08
  •  

    DwmExtendFrameIntoClientArea でなく,

    DwmEnableBlurBehindWindow でもダメなんでしたっけ?

    cf. DWM Blur Behind Overview

     

     

    質問の意味がわかっていないのかもしれませんが,

    AllowsTransparency を True にすると,

    WindowStyle が None にしないといけない関係で,

    そもそもタイトルバーは表示されないですよね?

    で,先のブログのサンプルでは,

    Grid をタイトルバーとして使うカラクリをいれてるコードがあります。

     

     

    2008年1月9日 9:46