Miz*_*zor 45 wpf binding popup
我有一个像这样定义的Popup:
<Popup
Name="myPopup"
StaysOpen="True"
Placement="Bottom"
PlacementRectangle="0,20,0,20"
PlacementTarget="{Binding ElementName=myPopupAnchor}">
<TextBlock ... />
</Popup>
Run Code Online (Sandbox Code Playgroud)
我已经myPopupAnchor
为事件MouseEnter
和元素添加了事件处理程序MouseLeave
.两个事件处理程序切换弹出窗口的可见性.
我的问题是myPopupAnchor的位置只在首次显示弹出窗口时被读取,或者被隐藏然后再次显示.如果锚移动,则弹出窗口不会移动.
我正在寻找解决这个问题的方法,我想要一个动人的Popup.我可以通知WPF PlacementTarget
绑定已更改并应再次读取吗?我可以手动设置弹出窗口的位置吗?
目前,我有一个非常粗略的解决方法,涉及关闭然后再次打开弹出窗口,这会导致一些重新绘制问题.
Nat*_*nAW 75
我看了几个选项并在那里打样.对我来说似乎最有用的事情是"碰撞"导致Popup自行重新定位的属性之一.我使用的属性是HorizontalOffset.
我将其设置为(本身+ 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;
};
}
Run Code Online (Sandbox Code Playgroud)
移动窗口时,弹出窗口将重新定位.不会注意到HorizontalOffset中的细微变化,因为窗口和弹出窗口仍然在移动.
我还在评估在其他交互过程中控件保持打开的情况下,弹出控件是否是最佳选项.我认为Ray Burns建议将这些东西放在Adorner层中似乎是一种适用于某些场景的好方法.
Jas*_*ank 26
只需添加到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>
Run Code Online (Sandbox Code Playgroud)
然后在代码隐藏中,为避免Window.GetWindow()
返回Null
,将处理程序连接到Loaded事件以容纳NathanAW的代码(例如,参见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;
};
}
}
}
Run Code Online (Sandbox Code Playgroud)
小智 21
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);
}
}
Run Code Online (Sandbox Code Playgroud)
如果你想移动弹出窗口,有一个简单的技巧:改变它的位置,然后设置:
IsOpen = false;
IsOpen = true;
Run Code Online (Sandbox Code Playgroud)
要补充 Jason Frank 的答案,Window.GetWindow()
如果 WPF UserControl 最终托管在 WinForms ElementHost 中,则该方法将不起作用。我需要找到的是我的 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);
}
Run Code Online (Sandbox Code Playgroud)
调用此辅助方法而不是并Window.GetWindow()
继续 Jason 的订阅正确事件的回答。对于 ScrollViewer,它是 ScrollChanged 事件。