Frage

Ich habe ein Popup wie folgt definiert:

<Popup
    Name="myPopup"
    StaysOpen="True"
    Placement="Bottom"
    PlacementRectangle="0,20,0,20"
    PlacementTarget="{Binding ElementName=myPopupAnchor}">
    <TextBlock ... />
</Popup>

Ich habe Event-Handler zum myPopupAnchor Elemente für die Ereignisse MouseEnter und MouseLeave hinzugefügt. Die beiden Event-Handler wechseln die Sichtbarkeit des Popup.

Mein Problem ist, die Position des myPopupAnchor wird nur gelesen, wenn das Popup zuerst angezeigt wird, oder ausgeblendet und dann wieder gezeigt. Wenn der Anker bewegt, das Popup nicht.

Ich bin die Suche nach Möglichkeiten, dies zu umgehen, ich will ein bewegtes Popup. Kann ich WPF mitteilen, dass der PlacementTarget hat sich geändert Bindung und sollte wieder gelesen werden? Kann ich manuell die Popup-Position eingestellt?

Zur Zeit habe ich eine sehr grobe Abhilfe, die Schließung beinhaltet und dann das Popup wieder zu öffnen, die einige Neulackierung Probleme verursacht.

War es hilfreich?

Lösung

schaute ich auf ein paar Optionen und Proben gibt. Die Sache, die für mich am besten zu funktionieren scheint, ist es, „bump“ eine der Eigenschaften, die das Popup verursacht selbst auf eigenem neu zu positionieren. Die Eigenschaft, die ich verwenden Horizontal.

gesetzt ich es (selbst + 1) und setzte es dann den ursprünglichen Wert zurück. Ich tue dies in einem Event-Handler, der ausgeführt wird, wenn das Fenster neu positioniert wird.

// Reference to the PlacementTarget.
DependencyObject myPopupPlacementTarget;

// Reference to the popup.
Popup myPopup; 

Window w = Window.GetWindow(myPopupPlacementTarget);
if (null != w)
{
    w.LocationChanged += delegate(object sender, EventArgs args)
    {
        var offset = myPopup.HorizontalOffset;
        myPopup.HorizontalOffset = offset + 1;
        myPopup.HorizontalOffset = offset;
    };
}

Wenn das Fenster bewegt wird, wird das Popup neu positionieren. Die subtile Veränderung der Horizontal ist nicht, weil die Fenster und Popup bemerkt ohnehin bereits in Bewegung.

Ich bin die Bewertung nach wie vor, ob ein Popup-Steuerelement die beste Option ist in Fällen, in denen die Steuerung während anderer Interaktion geöffnet bleibt. Ich denke, dass Ray Brennt Vorschlag, dieses Zeug in einem setzen Adorner Schicht scheint ein guter Ansatz für einige Szenarien.

Andere Tipps

Nur um Add-On zu NathanAW des großen Lösung oben, ich dachte, ich würde einige Kontexte darauf hin, , wie mit den C # -Code in diesem Fall zu platzieren. Ich bin immer noch ziemlich neu in WPF so kämpfte ich zuerst herauszufinden, wo NathanAW den Code zu setzen. Als ich versuchte, für das Benutzersteuerelement, dass Code im Konstruktor setzen, dass mein Popup gehostet, kehrte Window.GetWindow() immer Null (so die „Beule“ Code nie ausgeführt). Also dachte ich, dass andere Neulinge nicht sehen die Dinge im Kontext profitieren könnten.

Vor dem C # in Zusammenhang zeigt, ist hier einige Beispiel XAML Kontext einige relevante Elemente und ihre Namen zu zeigen:

<UserControl x:Class="MyNamespace.View1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >

    <TextBlock x:Name="popupTarget" />
    <Popup x:Name="myPopup"
           Placement="Bottom"
           PlacementTarget="{Binding ElementName=popupTarget}" >
         (popup content here)
    </Popup>
</UserControl>

Dann in der Code-Behind, um zu verhindern Window.GetWindow() Rückkehr Null mit, Draht einen Handler zum Loaded-Ereignisse bis zu beherbergen NathanAW Codes (siehe Peter Walke Kommentar auf einer ähnlichen Diskussion Stackoverflow zum Beispiel). Hier ist genau, wie alles sah in meinem Usercontrol-Code-behind:

public partial class View1 : UserControl
{
    // Constructor
    public View1()
    {
        InitializeComponent();

        // Window.GetWindow() will return Null if you try to call it here!             

        // Wire up the Loaded handler instead
        this.Loaded += new RoutedEventHandler(View1_Loaded);
    }

    /// Provides a way to "dock" the Popup control to the Window
    ///  so that the popup "sticks" to the window while the window is dragged around.
    void View1_Loaded(object sender, RoutedEventArgs e)
    {
        Window w = Window.GetWindow(popupTarget);
        // w should not be Null now!
        if (null != w)
        {
            w.LocationChanged += delegate(object sender2, EventArgs args)
            {
                var offset = myPopup.HorizontalOffset;
                // "bump" the offset to cause the popup to reposition itself
                //   on its own
                myPopup.HorizontalOffset = offset + 1;
                myPopup.HorizontalOffset = offset;
            };
            // Also handle the window being resized (so the popup's position stays
            //  relative to its target element if the target element moves upon 
            //  window resize)
            w.SizeChanged += delegate(object sender3, SizeChangedEventArgs e2)
            {
                var offset = myPopup.HorizontalOffset;
                myPopup.HorizontalOffset = offset + 1;
                myPopup.HorizontalOffset = offset;
            };
        }
    }
}
    private void ppValues_Opened(object sender, EventArgs e)
    {
        Window win = Window.GetWindow(YourControl);
        win.LocationChanged += new EventHandler(win_LocationChanged);            
    }
    void win_LocationChanged(object sender, EventArgs e)
    {
        if (YourPopup.IsOpen)
        {                
            var mi = typeof(Popup).GetMethod("UpdatePosition", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
            mi.Invoke(YourPopup, null);
        }
    }

Wenn Sie das Popup verschieben möchten, gibt es einen einfachen Trick: seine Position ändern, dann setzen:

IsOpen = false;
IsOpen = true;

Hinzufügen zu Jason Franks Antwort würde der Window.GetWindow() Ansatz nicht funktionieren, wenn die WPF Usercontrol schließlich in einem WinForms Elemente gehostet wird. Was ich brauchte, war zu finden die Scroll, dass mein Usercontrol platziert wurde in, als dass das Element der Rollbalken zeigt war.

Diese allgemeine rekursive Methode (modifiziert off eine andere Antwort) wird helfen, die Eltern eines bestimmten Typs in der logischen Struktur zu finden (es ist möglich, die visuelle Struktur zu verwenden), und es zurückgeben, wenn gefunden.

public static T FindLogicalParentOf<T>(DependencyObject child) where T: FrameworkElement
    {
        DependencyObject parent = LogicalTreeHelper.GetParent(child);

        //Top of the tree
        if (parent == null) return null;

        T parentWindow = parent as T;
        if (parentWindow != null)
        {
            return parentWindow;
        }

        //Climb a step up
        return FindLogicalParentOf<T>(parent);
    }

Rufen Sie diese Hilfsmethode statt Window.GetWindow() und weiterhin mit Jason Antwort auf die richtigen Ereignisse abonnieren möchte. Im Fall von Scroll, es ist das ScrollChanged Ereignis statt.

modifizierte ich den Code von Jason, weil das Popup bereits in den Vordergrund, wenn das Fenster nicht aktiviert ist. Gibt es eine Option im Popup-Klasse oder i ist meine Lösung ok?

private void FullLoaded(object sender, RoutedEventArgs e) {
Window CurrentWindow = Window.GetWindow(this.Popup);
if (CurrentWindow != null) {

    CurrentWindow.LocationChanged += (object innerSender, EventArgs innerArgs) => {
        this.RedrawPopup();
    };

    CurrentWindow.SizeChanged += (object innerSender, SizeChangedEventArgs innerArgs) => {
        this.RedrawPopup();
    };

    CurrentWindow.Activated += (object innerSender, EventArgs innerArgs) => {
        if (this.m_handleDeActivatedEvents && this.m_ShowOnActivated) {
            this.Popup.IsOpen = true;
            this.m_ShowOnActivated = false;
        }
    };

    CurrentWindow.Deactivated += (object innerSender, EventArgs innerArgs) => {
        if (this.m_handleDeActivatedEvents && this.Popup.IsOpen) {
            this.Popup.IsOpen = false;
            this.m_ShowOnActivated = true;
        }
    };

}
}

    private void RedrawPopup() {
        double Offset = this.Popup.HorizontalOffset;
        this.Popup.HorizontalOffset = Offset + 1;
        this.Popup.HorizontalOffset = Offset;
    }

Sie können dies nicht tun. Wenn Popup auf dem Bildschirm angezeigt wird, nicht neu positionieren sie nicht selbst wenn seine Eltern neu positioniert wird. Das ist das Verhalten von Popup-Steuerelement. check this: http://msdn.microsoft .com / en-us / library / system.windows.controls.primitives.popup.aspx

Sie können ein Fenster (mit Window = None) statt Popup verwenden, die Ihr Problem lösen können.

Laden Sie die Popup Popup Position Probe an:

http://msdn.microsoft. com / en-us / library / ms771558 (v = VS.90) aspx

Der Beispielcode verwendet die Klasse CustomPopupPlacement mit einem Rect-Objekt und bindet an horizontalen und vertikalen Versatz des Popup zu bewegen.

<Popup Name="popup1" Placement="Bottom" AllowsTransparency="True"
       IsOpen="{Binding ElementName=popupOpen, Path=IsChecked}"
       HorizontalOffset="{Binding ElementName=HOffset, Path=Value, Mode=TwoWay}"
       VerticalOffset="{Binding ElementName=VOffset, Path=Value, Mode=TwoWay}"
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top