我有一个像这样定义的弹出窗口:

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

我已将事件处理程序添加到 myPopupAnchor 事件的元素 MouseEnterMouseLeave. 。这两个事件处理程序切换弹出窗口的可见性。

我的问题是 myPopupAnchor 的位置仅在弹出窗口首次显示或隐藏然后再次显示时读取。如果锚点移动,弹出窗口不会移动。

我正在寻找解决这个问题的方法,我想要一个移动的弹出窗口。我可以通知 WPF PlacementTarget 绑定已更改,应重新阅读?我可以手动设置弹出窗口的位置吗?

目前,我有一个非常粗略的解决方法,涉及关闭然后再次打开弹出窗口,这会导致一些重画问题。

有帮助吗?

解决方案

我查看了几个选项和示例。对我来说最有效的方法是“碰撞”导致弹出窗口自行重新定位的属性之一。我使用的属性是 Horizo​​ntalOffset。

我将其设置为(本身+1),然后将其设置回原始值。我在重新定位窗口时运行的事件处理程序中执行此操作。

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

当窗口移动时,弹出窗口将重新定位。Horizo​​ntalOffset 中的细微变化不会被注意到,因为窗口和弹出窗口已经在移动。

我仍在评估弹出控件是否是在其他交互期间控件保持打开状态的情况下的最佳选择。我在想 Ray Burns 建议将这些东西放入装饰层中 对于某些场景来说似乎是一个好方法。

其他提示

仅仅添加到NathanAW的优秀解决方案,我认为我指出了一些背景,例如 其中 在这种情况下放置C#代码。我还是WPF的新手,所以我一开始就想弄清楚NathanAW的代码放在哪里。当我尝试将该代码放在托管我的Popup的UserControl的构造函数中时, Window.GetWindow()总是返回 Null (因此“bump”代码从未执行过) 。所以我认为其他新手可能会从上下文中看到事情中受益。

在上下文中显示C#之前,这里是一些示例XAML上下文,用于显示一些相关元素及其名称:

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

然后在代码隐藏中,为避免 Window.GetWindow()返回 Null ,将处理程序连接到Loaded事件以容纳NathanAW的代码(参见< a href =“https://stackoverflow.com/a/304604/718325”> Peter Walke关于类似stackoverflow讨论的评论。以下是我在UserControl代码隐藏中的所有内容:

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

如果你想移动弹出窗口,有一个简单的诀窍:改变它的位置,然后设置:

IsOpen = false;
IsOpen = true;

要添加到Jason Frank的答案,如果WPF UserControl最终托管在WinForms ElementHost中, Window.GetWindow()方法将无效。我需要找到的是我的UserControl所在的ScrollViewer,因为它是显示滚动条的元素。

这种通用的递归方法(修改了另一个答案)将有助于在逻辑树中找到特定类型的父级(也可以使用可视树),如果找到则返回它。

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

调用此辅助方法而不是 Window.GetWindow(),并继续Jason的订阅正确事件的答案。对于ScrollViewer,它改为ScrollChanged事件。

我从Jason修改了代码,因为如果窗口未激活,Popup已经在Foreground中。 Popup类中是否有任何选项,或者我的解决方案是否正确?

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

你不能这样做。当弹出窗口显示在屏幕上时,如果其父级被重新定位,则它不会重新定位。这是Popup控件的行为。 检查一下: http://msdn.microsoft的.com / EN-US /库/ system.windows.controls.primitives.popup.aspx

您可以使用Window(使用WindowStyle = None)代替Popup来解决您的问题。

在以下位置下载弹出式弹出位置示例

http://msdn.microsoft。 COM / EN-US /库/ ms771558(v = VS.90)的.aspx

代码示例使用带有Rect对象的CustomPopupPlacement类,并绑定到水平和垂直偏移以移动弹出窗口。

<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}"
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top