Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net ScrollViewer在调用ScrollToBottom()后不会停止滚动_.net_Wpf_Scroll_Scrollviewer - Fatal编程技术网

.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
a
Double.PositiveInfinity
值将设置为
VerticalOffset

/// <summary>
/// Vertically scroll to the end of the content.
/// </summary>
public void ScrollToBottom()
{
    EnqueueCommand(Commands.SetVerticalOffset, Double.PositiveInfinity, null);
}

ScrollViewer
设置实际的
VerticalOffset
,一切正常。

这应该是以下方面的解释:

如果调用
ScrollToBottom
a
Double.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问题来找到答案。