想象一下您打开WPF Popup
(例如通过ButtonClick)的情况。
您直接在ListBox
中有一些项目的Popup
,因此必须能够滚动。
想象一下,这是您的Custom Control
,它位于ScrollViewer
中。
现在,如果您将鼠标从Popup
表面移到外面并滚动,会发生什么?
上下滚动,但打开Popup
!这就是问题所在。
问题是,如何从控件内部检测到VisualTree中其他未知的父控件已开始滚动?
并连续设置IsDropDownOpen = false
?
最佳答案
我们可以编写一个触发器,以与ScrollViewer
中包含的元素一起使用。这是一个完整的示例应用程序:
<Grid>
<ScrollViewer VerticalAlignment="Top" Height="200">
<StackPanel HorizontalAlignment="Left">
<Button Name="button" Content="Open">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ei:ChangePropertyAction TargetObject="{Binding ElementName=popup}" PropertyName="IsOpen" Value="True"/>
</i:EventTrigger>
<local:ScrollTrigger>
<ei:ChangePropertyAction TargetObject="{Binding ElementName=popup}" PropertyName="IsOpen" Value="False"/>
</local:ScrollTrigger>
</i:Interaction.Triggers>
</Button>
<Popup Name="popup" PlacementTarget="{Binding ElementName=button}">
<TextBlock Background="White" Text="Sample text"/>
</Popup>
<Rectangle Width="100" Height="100" Fill="Red"/>
<Rectangle Width="100" Height="100" Fill="Green"/>
<Rectangle Width="100" Height="100" Fill="Blue"/>
<Rectangle Width="100" Height="100" Fill="Yellow"/>
</StackPanel>
</ScrollViewer>
</Grid>
我们有一个打开
Popup
的按钮,任何父ScrollViewer
中的滚动都会触发ScrollTrigger
操作,然后我们可以关闭弹出窗口。请注意,触发器是附加到Button
而不是Popup
的。我们可以使用视觉树中的任何附近元素。还要注意,我们使用另一个触发器来打开Popup
,但是如何打开ScrollTrigger
对原始问题并不重要。这是
ScrollTrigger
:class ScrollTrigger : TriggerBase<FrameworkElement>
{
protected override void OnAttached()
{
AssociatedObject.Loaded += new RoutedEventHandler(AssociatedObject_Loaded);
}
void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
{
foreach (var scrollViewer in GetScrollViewers())
scrollViewer.ScrollChanged += new ScrollChangedEventHandler(scrollViewer_ScrollChanged);
}
void scrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
InvokeActions(e.OriginalSource);
}
IEnumerable<ScrollViewer> GetScrollViewers()
{
for (DependencyObject element = AssociatedObject; element != null; element = VisualTreeHelper.GetParent(element))
if (element is ScrollViewer) yield return element as ScrollViewer;
}
}
ScrollChanged
非常简单,它仅附加到所有父ChangePropertyAction
事件并触发任何包含的 Action 。在示例中,我们使用Popup
关闭System.Windows.Interactivity
。如果您不熟悉行为,请安装Expression Blend 4 SDK并添加以下 namespace :
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
并将
Microsoft.Expression.Interactions
和ojit_code添加到您的项目中。关于WPF检测滚动父控件,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/2309883/