为什么ScrollViewer在删除项目时滚动到ItemsControl?

时间:2015-02-05 07:56:00

标签: wpf .net-3.5 scrollviewer itemscontrol

当这个ItemsControl的Items丢失元素时,ScrollViewer似乎有一个默认行为,使其滚动到ItemsControl。

举个例子:

<ScrollViewer>
    <ItemsControl>
        <TextBlock Text="Something"/>
        <TextBlock Text="Something"/>
        <TextBlock Text="Something"/>
        <TextBlock Text="Something"/>
        <TextBlock Text="Something"/>
        <TextBlock Text="Something"/>
        <TextBlock Text="Something"/>
        <TextBlock Text="Something"/>
        <TextBlock Text="Something"/>
        <TextBlock Text="Something"/>
        <ItemsControl>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
            <Button Click="ButtonBase_OnClick">
                <TextBlock Text="Some item"/>
            </Button>
        </ItemsControl>
    </ItemsControl>
</ScrollViewer>

使用ButtonBase_OnClick定义如下:

private void ButtonBase_OnClick(object sender, RoutedEventArgs e) {
    ((sender as Button).Parent as ItemsControl).Items.Remove(sender);
}

在采取任何行动之前,它看起来像这样:

How it looks at the start

但是,如果我点击一个按钮(它将从ItemsControl中删除):

How it looks after an item get removed

如果我添加项目而不是删除项目,则不会发生。我该如何防止这种行为?

修改

如果我添加此代码,则不会发生:

Loaded += (sender, args) => {
    new Thread(() => {
        Thread.Sleep(1500);
        Dispatcher.Invoke(new Action(() => {

            MyItemsControl.Items.Remove(MyItemsControl.Items[1]);
        }));
    }).Start();
};

但是,如果我添加:

(MyItemsControl.Items[1] as FrameworkElement).Focus();

在我删除之前,行为就会发生。

所以当任何项目被移除时都不会,但只有当项目具有焦点时才会被删除。因此,解决此问题的方法是在删除之前从项目中删除Focus。

有没有更方便的方法来阻止它发生?

编辑n°2

我没有说明我正在使用框架.Net v3.5。在@ Joseph的评论之后我用4.5.1尝试了它,事实上这在4.5.1中没有发生。

2 个答案:

答案 0 :(得分:1)

问题确实很棘手,我不确定以下是否是确切的解决方案,但肯定是一种解决方法。

我做的唯一更改是在点击事件中删除项目后添加一行(即将焦点从按钮或项目控件设置为父级或窗口)。

    private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
    {
        ((sender as Button).Parent as ItemsControl).Items.Remove(sender);

        this.Focus();
    }

我在上面进行了一个简单的测试并且已经实现了所需的行为,如果这不是您想要的,请告诉我吗?

答案 1 :(得分:1)

似乎(显然)会触发一些额外的滚动事件,我试图检查ScrollView收到的所有事件,但我仍然没有找到适当的解决这个bug的工作!

既然你需要使用.net 3.5这里有一个Old School hack,我希望它会有所帮助

首先添加ScrollChanged事件处理程序并命名您的ScrollViewer

       <ScrollViewer x:Name="sc" ScrollChanged="Sc_OnScrollChanged">            
        <ItemsControl >              
            <TextBlock Text="Something"/>
            <TextBlock Text="Something"/>

第二次将您的代码隐藏更改为以下

 private int _cpt;
    private double _save;
    private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
    {
        ((sender as Button).Parent as ItemsControl).Items.Remove(sender);
        _cpt = 0;
    }              
    private void Sc_OnScrollChanged(object sender, ScrollChangedEventArgs e)
    {
        if (_cpt < 3)
        {
            if (_cpt == 0)
            {
                _save = sc.VerticalOffset;
            }
            //sc.ScrollToTop();
            sc.ScrollToVerticalOffset(_save);
            _cpt++;
        }

    }

它有点像马铃薯解决方案,但它就像一个魅力。