为什么 ScrollViewer 在移除 Item 时滚动到 ItemsControl?
Why do ScrollViewer scroll to ItemsControl when an Item is removed?
ScrollViewer 似乎有一个默认行为,当此 ItemsControl 的 Items 丢失一个元素时,它会滚动到 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);
}
在执行任何操作之前,它看起来像这样:
但是,如果我单击一个按钮(它将从 ItemsControl 中删除):
如果我添加一项而不是删除一项,则不会发生这种情况。我怎样才能防止这种行为?
编辑
如果我添加这段代码就不会发生:
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();
就在我删除它之前,出现了这种行为。
所以它不是在任何项目被删除时,而是只有在项目具有焦点时。因此,解决此行为的一种方法是在删除 Item 之前将 Focus 从 Item 中移除。
有没有更方便的方法阻止它发生?
编辑 n°2
我没有指定我正在使用 .Net v3.5 框架。我在@Joseph 的评论后用 4.5.1 试了一下,确实这在 4.5.1 中没有发生。
这个问题真的很棘手,我不确定下面是否是确切的解决方案,但它确实是一种解决方法。
我所做的唯一更改是在单击事件中删除项目后添加一行(即将按钮或项目控件的焦点设置到父级或 Window)。
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
((sender as Button).Parent as ItemsControl).Items.Remove(sender);
this.Focus();
}
我 运行 完成了一个具有上述要求的简单测试,如果这不是您要找的,请告诉我?
似乎(很明显)触发了一些额外的滚动事件,我试图检查 ScrollView
收到的所有事件,但我仍然没有想出解决这个错误的正确方法!
并且由于您需要在此处使用 .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++;
}
}
它有点像 Potato 解决方案,但它的效果非常好。
ScrollViewer 似乎有一个默认行为,当此 ItemsControl 的 Items 丢失一个元素时,它会滚动到 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);
}
在执行任何操作之前,它看起来像这样:
但是,如果我单击一个按钮(它将从 ItemsControl 中删除):
如果我添加一项而不是删除一项,则不会发生这种情况。我怎样才能防止这种行为?
编辑
如果我添加这段代码就不会发生:
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();
就在我删除它之前,出现了这种行为。
所以它不是在任何项目被删除时,而是只有在项目具有焦点时。因此,解决此行为的一种方法是在删除 Item 之前将 Focus 从 Item 中移除。
有没有更方便的方法阻止它发生?
编辑 n°2
我没有指定我正在使用 .Net v3.5 框架。我在@Joseph 的评论后用 4.5.1 试了一下,确实这在 4.5.1 中没有发生。
这个问题真的很棘手,我不确定下面是否是确切的解决方案,但它确实是一种解决方法。
我所做的唯一更改是在单击事件中删除项目后添加一行(即将按钮或项目控件的焦点设置到父级或 Window)。
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
((sender as Button).Parent as ItemsControl).Items.Remove(sender);
this.Focus();
}
我 运行 完成了一个具有上述要求的简单测试,如果这不是您要找的,请告诉我?
似乎(很明显)触发了一些额外的滚动事件,我试图检查 ScrollView
收到的所有事件,但我仍然没有想出解决这个错误的正确方法!
并且由于您需要在此处使用 .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++;
}
}
它有点像 Potato 解决方案,但它的效果非常好。