我有两个控件,一个TextBlock和一个PopUp.当用户在文本块上单击(MouseDown)时,我想显示弹出窗口.我认为我可以在Popup上使用EventTrigger执行此操作,但我不能在EventTrigger中使用setter,我只能启动故事板.我想在XAML中严格执行此操作,因为这两个控件都在模板中,我不知道如何在代码中找到弹出窗口.
这是概念上我想做的,但不能,因为你不能把一个setter放在EventTrigger中(就像你可以使用DataTrigger):
Some text ...
当事件发生在不同的控件上时,在XAML中严格显示弹出窗口的最佳方法是什么?
我做了一些简单的事,但它确实有效.
我使用了一个典型的ToggleButton,我通过更改其控件模板将其重新设置为文本块.然后我将ToggleButton上的IsChecked属性绑定到弹出窗口上的IsOpen属性.Popup有一些像StaysOpen这样的属性可以让你修改关闭行为.
以下适用于XamlPad.
Click Me Here!! I'm the popup
以下方法与Helge Klein相同,只是当您单击Popup外部的任何位置时弹出窗口自动关闭(包括ToggleButton本身):
"BoolInverter"用于IsHitTestVisible绑定,因此当您再次单击ToggleButton时,弹出窗口将关闭:
public class BoolInverter : MarkupExtension, IValueConverter
{
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is bool)
return !(bool)value;
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return Convert(value, targetType, parameter, culture);
}
}
...它显示了将IValueConverter和MarkupExtension组合在一起的便捷技术.
我确实发现了这种技术的一个问题:当屏幕上同时出现两个弹出窗口时,WPF有问题.具体来说,如果您的切换按钮位于工具栏中的"溢出弹出窗口"中,则单击它后将打开两个弹出窗口.然后,当您单击窗口上的任何其他位置时,您可能会发现第二个弹出窗口(您的弹出窗口)将保持打开状态.那时,关闭弹出窗口很困难.用户无法再次单击ToggleButton来关闭弹出窗口,因为IsHitTestVisible为false,因为弹出窗口已打开!在我的应用程序中,我不得不使用一些黑客来缓解这个问题,例如主窗口上的以下测试,其中(以路易斯布莱克的声音说)"如果弹出窗口打开并且用户在弹出窗口外的某处点击,关闭friggin'弹出窗口.":
PreviewMouseDown += (s, e) =>
{
if (Popup.IsOpen)
{
Point p = e.GetPosition(Popup.Child);
if (!IsInRange(p.X, 0, ((FrameworkElement)Popup.Child).ActualWidth) ||
!IsInRange(p.Y, 0, ((FrameworkElement)Popup.Child).ActualHeight))
Popup.IsOpen = false;
}
};
// Elsewhere...
public static bool IsInRange(int num, int lo, int hi) =>
num >= lo && num <= hi;
怎么样:
请注意,它Popup
是Button
按名称引用,反之亦然.所以x:Name="..."
两者都需要,Popup
而且Button
.
实际上可以通过Storyboard
使用本SO答案中SetProperty
描述的自定义EventTrigger Action 替换内容来进一步简化
我的MouseDown部分有一些问题,但这里有一些代码可能会让你开始.
Test Popup Content