WPF检测滚动父控件

PaN*_*1Me 9 wpf scroll custom-controls scrollviewer

想象一下你打开WPF的情况Popup(例如通过ButtonClick).您可以ListBox直接Popup使用某些项目,因此您必须能够滚动.想象一下,这是你的Custom Control,它位于ScrollViewer.

现在如果你用鼠标移动到Popup表面并滚动,会发生什么?你可以向上和向下滚动但是Popup打开了!这就是问题所在.

问题是,如何从Control内部检测到VisualTree中的其他一些未知的Parent Control已经开始滚动?并连续设定IsDropDownOpen = false

Ric*_*key 10

我们可以编写一个触发器,用于包含在a中的元素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>
Run Code Online (Sandbox Code Playgroud)

我们有一个打开的按钮,Popup任何父级的任何滚动都会ScrollViewer导致ScrollTrigger触发操作,然后我们可以关闭弹出窗口.请注意,触发器附加到Button而不是Popup.我们可以使用可视树中的任何附近元素.另请注意,我们使用另一个触发器来打开,Popup但它如何打开对原始问题并不重要.

这是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;
    }
}
Run Code Online (Sandbox Code Playgroud)

ScrollTrigger非常简单,它只是附加到所有父ScrollChanged事件并触发任何包含的操作.在样本中我们使用ChangePropertyAction关闭Popup.

如果您不熟悉行为,请安装Expression Blend 4 SDK并添加以下命名空间:

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
Run Code Online (Sandbox Code Playgroud)

并添加System.Windows.InteractivityMicrosoft.Expression.Interactions到项目中.