4

WPFはそのコンテンツをウィンドウの背景としてレンダリングすると言っても過言ではありません。従来のHWNDの意味での子ウィンドウはありません。そのため、WebBrowserなどのWPFアプリに基づくHWNDを導入すると、外観の点で問題が発生し始めます。

WebBrowserとTextBoxなどの2つの子を持つグリッドを持つウィンドウについて考えてみます。代わりにWebBrowserが赤い円の場合、TextBoxはその上にレンダリングされます。WebBrowserの場合、TextBoxはどこにも見つかりません。これは、TextBoxがメインウィンドウの背景としてレンダリングされ、WebBrowserが実際にはメインウィンドウのHWNDの子であり、背景を覆い隠しているためです。

したがって、すべてがうまくいっています(そうではありません)。どのようにして望ましい振る舞いを達成しますか?WebBrowserの上にTextBoxをレンダリングしたい。誰かがこの問題に遭遇しましたか?

私は、2番目の透明なトップレベルのボーダレスWPFウィンドウを作成し、メインウィンドウがそれを所有するように親を再設定し、それを実現するために他のトリックを実行することを考えています。

掘り下げる前に、誰かが明白なまたはより単純な解決策を持っているかどうか疑問に思いましたか?


Meleakによる更新

Ray Burns Answerの実装を投稿できる人なら誰にでも、この報奨金を提供していますAirRepair。私は自分で試しましたが無駄でした

4

4 に答える 4

2

WPFの相互運用:「空域」とウィンドウ領域の概要を読んでください。

于 2010-03-10T16:25:01.440 に答える
1

推奨される解決策

このシグネチャを持つ単純な「AirRepair」クラスをお勧めします。

public class AirRepair : Decorator
{
  public HwndHost Win32Host ... // DP bound to HwndHost
  public Geometry RepairArea ... // Default is entire decorated control,
                                 // or use OpacityMask
}

このように使用:

<Grid>
  <WebBrowser x:Name="browser" ... />

  <AirRepair Win32Host="{Binding ElementName=browser}"
             Margin="10" HorizontalAlignment="Left" ...>
    <TextBox ... />
  </AirRepair>
</Grid>

AirRepairは、、、またはその他の任意ので使用WebBrowserできWindowsFormsHostますHwndHost。装飾されたコントロールでカバーされる領域は、Win32コンテンツ内に表示され、フォーカスイベントとマウスイベントを受け入れます。長方形以外の装飾が施されたコントロールの場合、表示する領域は、RepairAreaおよび/またはOpacityMaskプロパティで指定できます。

使い方

AirRepairは、次の方法で空域の問題を解決します。

  1. HwndHost与えられた使用の下で子hWndを作成するHwndSource
  2. そのhRgnを適切な領域に設定する
  3. 装飾されたコントロールのaにRootVisual設定するBorderBackgroundVisualBrush
  4. WM_MOUSEMOVE子hWndが受信したWPFメインウィンドウへの転送など

この結果、WPFは引き続きWin32コンテンツの背後にコンテンツを描画しますが、AirRepairの子ウィンドウは別のWin32コントロールのWin32コンテンツの前に同じコンテンツを再描画します。

いくつかの重要な実装の詳細

親hWndを取得する

が最初に設定された場合Win32Host、hWndがある場合とない場合があります。は/をPropertyChangedCallback使用して可能なhWnd変更を検出し、コールバックで独自のhWndポインターを更新して、イベントの処理を終了できるようにする必要があります。PresentationSource.AddSourceChangedHandlerPresentationSource.RemoveSourceChangedHandlerDispatcher.BeginInvokeHwndHostSourceChanged

子の作成hWnd

子hWndは、HwndSourceクラスを使用して作成、ペアレント化、およびマネージコードにフックできます。Win32Hostの親hWndが使用できなくなったら、必ず廃棄してください。

子の配置hWnd

子hWndのウィンドウ位置(その親に対する)は、次のように計算できます。

 var compositionTarget = PresentationSource.FromVisual(this).CompositionTarget;
 var position = compositionTarget.TransformToDevice(
                  this.TransformToVisual(Win32Host));

イベントは、UIELement.LayoutUpdatedこれを最新の状態に保つために使用する必要があります。

hRgnと不透明度の計算

オプション:長方形の修復領域のみがサポートされている場合は省略します

RepairAreaorOpacityMaskが設定されていて、子hWndが存在する場合は、aを使用してを使用してペイントRenderTargetBitmapし、そこからhRgnを作成します。nullの場合、長方形を使用します。nullの場合、黒を使用します。サイズは、AirRepairデコレータの座標をデバイスの座標に変換することによって設定されます。これは、アニメートされたブラシや変化しているaなどの変数を適切に処理しないことに注意してください。RepairAreaOpacityMaskRepairAreaOpacityMaskRenderTargetBitmapOpacityMaskVisualBrushVisual

子hWndにコンテンツを描画する

装飾されたコントロールではなく、AirRepairデコレータであるaVisualBrushを使用します。Visualこれにより、コンテンツを変更せずに装飾されたコントロールを置き換えることができます。

childHwndSource.RootVisual =
  new Border
  {
    Background = new VisualBrush
    {
      Visual = this,
      ViewBoxUnits = BrushMappingMode.Absolute,
      ViewPortUnits = BrushMappingMode.Absolute,
    }
  };

マウスメッセージの転送

を使用してフックを追加してから、 HwndSource.AddHookWin32PostMessageをコンテナに使用します。

childHwndSource.AddHook((hwnd, msg, wParam, lParam, handled) =>
{
  // Check if message needs forwarding and update parameters if necessary
  switch(msg)
  {
    default:
      return;  // Not recognized - do not forward

    case WM_MOUSEMOVE:
    ...
  }
  var target = PresentationSource.FromVisual(this).CompositionTarget as HwndTarget;
  if(target!=null)
    Win32Methods.PostMessage(target.Handle, msg, wParam, lParam);
};
于 2010-03-11T00:07:25.070 に答える
1

すばやく簡単な解決策をお探しの場合は、ポップアップコントロールを使用してください。例を次に示します。

http://karlshifflett.wordpress.com/2009/06/13/wpf-float-buttons-over-web-browser-control/

于 2010-09-10T17:49:00.770 に答える
0

特にWebブラウザーをターゲットにしている場合は、これを2、3回試みています。 Chris Cavanaghは、Chromeをベースにした優れたソリューションを作成しました。

于 2010-03-10T21:57:32.093 に答える