2011-01-08 10 views

risposta

5

Come fa notare Andrei, questo comportamento è in profondità all'interno del controllo Popup e difficile da superare. Se sei disposto a fare del lavoro, puoi farlo ridimensionando e traducendo il contenuto del popup quando raggiunge i bordi dello schermo. Ai fini della dimostrazione, ci concentreremo sul bordo sinistro dello schermo.

Se abbiamo qualche XAML come questo:

<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> 

e code-behind in questo modo:

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; 
} 

poi calcolando che il Popup sarebbe off-screen, siamo in grado di ridurre la larghezza del contenuto e assegnargli un margine negativo in modo che la porzione sullo schermo sia ritagliata rispetto a ciò che sarebbe apparso se lo Popup consentisse di farlo.

Questo dovrebbe essere esteso per trattare tutti e quattro i bordi dello schermo e la possibilità di schermi multipli, ma dimostra che l'approccio è praticabile.

1

Non penso che ci sia un modo per farlo. Almeno un modo pulito. Se sbirci alla classe Popup con Reflector, troverai un metodo UpdatePosition che regolerà la posizione del popup in modo che rimanga tra i limiti dello schermo. Questo metodo viene chiamato da più punti, dai callback On***Changed (OnPlacementChanged, OnVerticalOffsetChanged, ecc.).

Se sei veramente vuole veramente ottenere questa funzionalità, si potrebbe avere una piccola possibilità di estendere la classe Popup, ignorare alcuni dei metadati sulle proprietà che hanno registrato con le On***Changed callback in modo che UpdatePosition mai viene chiamato, tuttavia la maggior parte delle persone prenderà in considerazione l'idea di fare questo per essere puro male, non lo consiglio neanche io.

0

È possibile utilizzare il controllo PrecisePopup dalla libreria opensource JungleControls. Posizionerà il popup esattamente come specificato anche se questo significa che il popup è parzialmente fuori schermo.

È possibile selezionare automaticamente il posizionamento più adatto tra i posizionamenti definiti, ma se è necessario un solo posizionamento popup corrispondente al posizionamento "In basso" del Popup incorporato, è possibile farlo in questo modo:

<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

È necessario posizionare il popup e il relativo target all'interno del pannello Canvas in modo che non si riposizionino a causa del problema del bordo dello schermo nel controllo popup.

  <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> 

Dal momento che l'intera unità si trova all'interno del pannello di tela e il posizionamento rettangolo viene impostato il popup sarà mostrata sotto il rettangolo.

+0

Questa soluzione non funziona per me. Spostando il mio popup vicino al bordo dello schermo si riposiziona di conseguenza indipendentemente dal contenitore Canvas. Ho provato un obiettivo di posizionamento tra pari e l'utilizzo del genitore predefinito. – Brannon

0

non c'è modo sul quadro WPF per mettere Popup fuori dello schermo, ma è possibile forzare la posizione popup chiamando "SetWindowPos" tramite P/Invoke:

#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); 

      } 


     } 
Problemi correlati