1

ログ メッセージを表示するItemsControl内にを含むアプリケーションのビューがあります。ScrollViewerメッセージである文字列のコレクションはObservableCollection<string>、ビューモデル内にあります。

新しいメッセージが追加さScrollViewerれると、チェックボックスがチェックされているかどうかに応じて、リストの一番下までスクロールする必要があります。これを完全にビューで処理したいと思います。まともな解決策を見つけました(here)。このチェックボックスは、最初はデフォルトでオンになっています。

ただし、奇妙な動作が見られます。

  • メッセージが追加される前に、チェックボックスをオフにしてリストにメッセージを追加すると、リストはスクロールしません (正しい動作)。
  • チェックボックスをオンのままにしてメッセージを追加すると、リストがスクロールします (正しい動作)。
  • リストにいくつかのメッセージを追加してから、ボックスのチェックを外してからリストに追加すると、リストはスクロールします (不正な動作)。

以下に示す問題を示す非常に単純な 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));
    }
}
4

1 に答える 1

1

これは、ScrollViewer Source Codeからの説明である必要があります。

値を呼び出すとScrollToBottomDouble.PositiveInfinityとして設定されVerticalOffsetます。

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

新しいアイテムを追加するScrollViewerと、ビューが最後に更新されます。VerticalOffsetこれは、最後PositiveInfinityまでスクロールすることを意味します。と

var verticalOffset = MessagesScrollViewer.VerticalOffset;
MessagesScrollViewer.ScrollToVerticalOffset(verticalOffset)‌​;

ScrollViewer実数VerticalOffsetを設定すると、すべて問題ありません。

于 2013-10-18T20:01:40.687 に答える