.net ScrollViewer在调用ScrollToBottom()后不会停止滚动
我的应用程序中有一个视图,其中包含一个.net ScrollViewer在调用ScrollToBottom()后不会停止滚动,.net,wpf,scroll,scrollviewer,.net,Wpf,Scroll,Scrollviewer,我的应用程序中有一个视图,其中包含一个滚动查看器中的项控件,用于显示日志消息。作为消息的字符串集合是my viewmodel中的一个ObservableCollection 添加新消息时,ScrollViewer需要滚动到列表底部,具体取决于是否选中复选框。我想完全从这个角度来处理这个问题。我找到了一个不错的解决办法()。默认情况下,最初选中该复选框 但我看到了奇怪的行为: 在添加任何消息之前,如果我取消选中复选框并将消息添加到列表中,列表不会滚动(正确的行为) 如果我选中复选框并添加消息,列
滚动查看器中的项控件
,用于显示日志消息。作为消息的字符串集合是my viewmodel中的一个ObservableCollection
添加新消息时,ScrollViewer
需要滚动到列表底部,具体取决于是否选中复选框。我想完全从这个角度来处理这个问题。我找到了一个不错的解决办法()。默认情况下,最初选中该复选框
但我看到了奇怪的行为:
- 在添加任何消息之前,如果我取消选中复选框并将消息添加到列表中,列表不会滚动(正确的行为)
- 如果我选中复选框并添加消息,列表将滚动(正确的行为)
- 如果我向列表中添加了一些消息,然后取消选中该框,然后向列表中添加更多消息,则列表仍会滚动(错误行为)
我将其提炼为一个非常简单的WPF应用程序,演示了这个问题,如下所示
这是什么原因造成的?如何修复
XAML:
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="229" Width="551">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<CheckBox Grid.Row="0" Content="Autoscroll?" Name="AutoscrollCheckBox" IsChecked="True" />
<Button Grid.Row="1" Content="Add a message" Name="AddMessageButton" Click="AddMessageButton_Click" />
<ScrollViewer Name="MessagesScrollViewer" Grid.Row="2">
<ItemsControl Name="MessagesList" ItemsSource="{Binding Messages}" />
</ScrollViewer>
</Grid>
</Window>
以及背后的代码:
public partial class MainWindow : Window, INotifyPropertyChanged {
public MainWindow() {
InitializeComponent();
DataContext = this;
((INotifyCollectionChanged)MessagesList.Items).CollectionChanged += Messages_CollectionChanged;
}
private void Messages_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) {
Console.WriteLine((bool)AutoscrollCheckBox.IsChecked);
if (AutoscrollCheckBox.IsChecked.HasValue && (bool)AutoscrollCheckBox.IsChecked && (e.Action == NotifyCollectionChangedAction.Add))
MessagesScrollViewer.ScrollToBottom();
}
private ObservableCollection<string> m_Messages = new ObservableCollection<string>();
public ObservableCollection<string> Messages {
get { return m_Messages; }
set { m_Messages = value; NotifyPropertyChanged("Messages"); }
}
private int _msgNumber = 0;
private void AddMessageButton_Click(object sender, RoutedEventArgs e) {
Messages.Add(String.Format("Message #{0}", _msgNumber++));
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string name) {
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
public分部类主窗口:窗口,INotifyPropertyChanged{
公共主窗口(){
初始化组件();
DataContext=this;
((INotifyCollectionChanged)MessagesList.Items)。CollectionChanged+=消息\u CollectionChanged;
}
私有无效消息\u CollectionChanged(对象发送方,NotifyCollectionChangedEventArgs e){
WriteLine((bool)AutoscrollCheckBox.IsChecked);
if(AutoscrollCheckBox.IsChecked.HasValue&&(bool)AutoscrollCheckBox.IsChecked&(e.Action==NotifyCollectionChangedAction.Add))
MessagesScrollViewer.ScrollToBottom();
}
私有ObservableCollection m_Messages=新ObservableCollection();
公共可观察收集消息{
获取{返回m_消息;}
设置{m_Messages=value;NotifyPropertyChanged(“Messages”);}
}
私有整数_msgNumber=0;
私有void AddMessageButton_单击(对象发送者,路由目标){
Messages.Add(String.Format(“Message#{0},_msgNumber++”);
}
公共事件属性更改事件处理程序属性更改;
私有void NotifyPropertyChanged(字符串名称){
if(PropertyChanged!=null)
PropertyChanged(此,新PropertyChangedEventArgs(名称));
}
}
这应该是以下方面的解释:
如果调用ScrollToBottom
aDouble.PositiveInfinity
值将设置为VerticalOffset
/// <summary>
/// Vertically scroll to the end of the content.
/// </summary>
public void ScrollToBottom()
{
EnqueueCommand(Commands.SetVerticalOffset, Double.PositiveInfinity, null);
}
ScrollViewer
设置实际的VerticalOffset
,一切正常。这应该是以下方面的解释:
如果调用ScrollToBottom
aDouble.PositiveInfinity
值将设置为VerticalOffset
/// <summary>
/// Vertically scroll to the end of the content.
/// </summary>
public void ScrollToBottom()
{
EnqueueCommand(Commands.SetVerticalOffset, Double.PositiveInfinity, null);
}
ScrollViewer
设置实际的VerticalOffset
,一切正常。滚动到新项目是默认行为。如果IsChecked为False,则必须停止此操作,而不是在IsChecked为True时调用ScrollToBottom。(+1用于提供运行样本)这不正确。注释掉订阅事件的构造函数的最后一行,不会出现滚动。哦,你说得对。我看到一个不断变化的滚动条,但这是因为新的项目。对不起,我没有解释,只有一个解决方法:添加else MessagesScrollViewer.ScrollToVerticalOffset(MessagesScrollViewer.VerticalOffset)邮件中的代码>收集已更改。这似乎停止了这种奇怪的行为。滚动到新项目是默认行为。如果IsChecked为False,则必须停止此操作,而不是在IsChecked为True时调用ScrollToBottom。(+1用于提供运行样本)这不正确。注释掉订阅事件的构造函数的最后一行,不会出现滚动。哦,你说得对。我看到一个不断变化的滚动条,但这是因为新的项目。对不起,我没有解释,只有一个解决方法:添加else MessagesScrollViewer.ScrollToVerticalOffset(MessagesScrollViewer.VerticalOffset)邮件中的代码>收集已更改。这似乎停止了这种奇怪的行为。感谢您花时间深入了解这一点!另外还有一个建议。现在我们知道了它们之间的关系,也许你可以编辑问题标题和标签来帮助其他人解决这个唯一的ScrollViewer问题,从而找到答案。感谢你花时间深入研究这个问题!另外还有一个建议。现在我们知道了它们之间的关系,也许你可以编辑问题标题和标签来帮助其他人解决这个唯一的ScrollViewer问题来找到答案。