2011-01-08 18 views
10

オフスクリーンになったときにWPF Popupの位置を変更しないようにする方法はありますか?WPFポップアップが画面外になったときにポップアップの位置を変更しないようにする方法はありますか?

私はこれを見つけましたold question、しかしそれに適切な答えを得ていませんでした。これを行う方法はありますか?私は必要に応じてそれをサブクラス化します。ありがとう。

答えて

5

Andreiは指摘しているように、この動作はコントロール内の深い部分であり、克服するのは難しいです。いくつかの作業をしたい場合は、画面の端に達したときにポップアップのコンテンツのサイズを変更して翻訳することによって行うことができます。デモンストレーションの目的のために、画面の左端に焦点を当てます。

私たちはこのようないくつかのXAMLお持ちの場合:このような

<Window ... 
     LocationChanged="Window_LocationChanged" 
     SizeChanged="Window_SizeChanged" 
     > 
    <Grid> 
     <Rectangle Name="rectangle1" Width="100" Height="100" Fill="Blue"/> 
     <Popup Name="popup1" PlacementTarget="{Binding ElementName=rectangle1}" IsOpen="True" Width="100" Height="100"> 
      <TextBlock Background="White" TextWrapping="Wrap" Width="100" Height="100"> 
       <TextBlock.Text>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</TextBlock.Text> 
      </TextBlock> 
     </Popup> 
    </Grid> 
</Window> 

とコードビハインド:

private void Window_LocationChanged(object sender, EventArgs e) 
{ 
    RefreshPopupPosition(); 
} 

private void Window_SizeChanged(object sender, SizeChangedEventArgs e) 
{ 
    RefreshPopupPosition(); 
} 

private void RefreshPopupPosition() 
{ 
    var upperLeft = rectangle1.PointToScreen(new Point(0, 100)); 
    var xOffset = Math.Min(0, upperLeft.X); 
    popup1.Width = xOffset + 100; 
    (popup1.Child as FrameworkElement).Margin = new Thickness(xOffset, 0, 0, 0); 
    popup1.HorizontalOffset += 1; 
    popup1.HorizontalOffset -= 1; 
} 

を、その後Popupがオフスクリーンになることを計算することで、私たちが幅を小さくすることができますPopupがこれを許可する場合、表示されていた部分がクリップされて、表示されている部分がクリップされます。

これは、画面の4つのエッジと複数の画面の可能性を処理するために拡張する必要がありますが、アプローチが実行可能であることを示しています。

1

私はこれを行う方法はないと思います。少なくともきれいな方法。 ReflectorでPopupクラスを覗くと、UpdatePositionメソッドが見つかるでしょう。このメソッドは、画面境界の間にとどまるようにポップアップの位置を調整します。このメソッドは、On***Changedコールバック(OnPlacementChangedOnVerticalOffsetChangedなど)からいくつかの場所から呼び出されます。

実際にこの機能を使用したい場合は、UpdatePositionが呼び出されないように、On***Changedコールバックで登録されたプロパティのメタデータの一部をオーバーライドし、Popupクラスを拡張する可能性があります。ほとんどの人はこれを純粋な悪であると考えますが、私はそれをお勧めしません。

0

私のopensource JungleControlsライブラリからPrecisePopupコントロールを使用できます。ポップアップが部分的に画面外にある場合でも、指定されたとおりにポップアップを正確に配置します。

定義したプレースメントの中から最適なプレースメントを自動的に選択できますが、組み込みポップアップの「ボトム」配置に対応する1つの正確なポップアッププレースメントが必要な場合は、

<jc:PrecisePopup PlacementTarget="{Binding ElementName=SomeTarget}" 
       IsOpen="{Binding IsOpen}"> 
    <jc:PrecisePopup.Placements> 
     <jc:PrecisePopupPlacement VerticalTargetAlignment="Bottom" /> 
    </jc:PrecisePopup.Placements> 
    <!-- Popup content here... --> 
</jc:PrecisePopup> 
-1

ポップアップコントロールの画面エッジの問題により、ポップアップとそのターゲットをキャンバスパネルの内側に配置する必要があります。

  <Canvas> 
      <Rectangle Name="rectPopUp" Width="30" Height="30"/> 
      <Button Width="20" Height="20" Name="btnAppLauncher" Click="btnAppLauncher_Click" Margin="-5,-2,0,0"> 
       <Button.Content> 
        <Path Fill="White" Stretch="Uniform" Data="M16,20H20V16H16M16,14H20V10H16M10,8H14V4H10M16,8H20V4H16M10,14H14V10H10M4,14H8V10H4M4,20H8V16H4M10,20H14V16H10M4,8H8V4H4V8Z"></Path> 
       </Button.Content> 
      </Button> 
      <Popup Name="pnlAppLauncherPopup" PlacementRectangle="0,25,0,0" PlacementTarget="{Binding ElementName=btnAppLauncher}" Placement="Bottom" AllowsTransparency="True" PopupAnimation="Slide"> 
       <UniformGrid Name="pnlAppLauncher"> 
       </UniformGrid> 
      </Popup> 
     </Canvas> 

ユニット全体がキャンバスパネル内にあり、配置矩形が設定されているため、ポップアップが矩形の下に表示されます。

+0

このソリューションは、私のために動作しません。ポップアップを画面の端の近くで動かすと、キャンバスコンテナに関係なく、ポップアップがそれに応じて再配置されます。私は、デフォルトの親を使用するだけでなく、ピア配置ターゲットを試しました。 – Brannon

0

は、画面の外にポップアップを置くためのWPFフレームワークに方法はありませんが、あなたは、p /呼び出しを経由して「SetWindowPos」を呼び出すことによって、ポップアップ位置を強制することができます。

#region P/Invoke imports & definitions 

     private const int HWND_TOPMOST = -1; 
     private const int HWND_NOTOPMOST = -2; 
     private const int HWND_BOTTOM = 1; 
     private const int SWP_NOMOVE = 0x0002; 
     private const int SWP_NOSIZE = 0x0001; 
     private const int SWP_NOACTIVATE = 0x0010; 
     private const int GW_HWNDPREV = 3; 
     private const int GW_HWNDLAST = 1; 


    [DllImport("user32.dll", EntryPoint = "SetWindowPos")] 
     private static extern int SetWindowPos(IntPtr hWnd, int hwndInsertAfter, int x, int y, int cx, int cy, int wFlags); 

#endregion 

private void updateposition(Item item) 
     { 
      if (item.IsOpen) 
      { 
       IntPtr hwnd = ((HwndSource)PresentationSource.FromVisual(item.popup.Child)).Handle; 
       SetWindowPos(hwnd, 0, (int)item.WorkPoint.X, (int)item.WorkPoint.Y, (int)item.popup.Width, (int)item.popup.Height, SWP_NOSIZE | SWP_NOACTIVATE); 

      } 


     } 
関連する問題