将项目添加到ObservableCollection时发生WPF事件

时间:2019-09-03 02:23:28

标签: c# wpf event-handling

我遇到了ObservableCollection CollectionChanged事件的问题。我有一个包含listView的MainWindow.xaml文件,并且使用代码行为着重于listView中新添加(或修改)的元素。

let e = {
  id: 1,
  name: 'some name'
}

var div = document.createElement("DIV");

let content = `<h5>usuario:</h5> ${e.name} 
        <h5>id: </h5>${e.id}
        `;

div.innerHTML = content
document.body.appendChild(div);
<ListView x:Name="recordListView" Grid.Row="0" Grid.Column="0" Height="Auto" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
                 ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.HorizontalScrollBarVisibility="Visible" Margin="20,20,20,10"
                 AlternationCount="2" 
                 ItemsSource="{Binding Path=SessionRecords}" FontSize="14" > 
…
</ListView>

您可能会注意到我使用了ViewModel。

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new MainWindowViewModel();
        }

        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            var mainWindowViewModel = (MainWindowViewModel)DataContext;
            mainWindowViewModel.SessionRecords.CollectionChanged += SessionRecords_CollectionChanged;
        }

        private void SessionRecords_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (e.NewItems?[0] != null)
            {
                recordListView.ScrollIntoView(e.NewItems[0]);
            }
        }
    }

在运行时,当我向可观察的集合中添加新项目时,会在该项目出现在屏幕上之前引发更改集合的事件。在元素出现在屏幕上后,如何确保引发事件?或者我该怎么做才能确保网格始终滚动并集中显示新添加或现有修改的项目?不管是否使用MVVM,我都不在乎。

2 个答案:

答案 0 :(得分:1)

尝试一下。仅在具有更高优先级的UI更新之后才会执行。

Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(() =>
{
    recordListView.ScrollIntoView(e.NewItems[0]);
}));

有关Dispatcher.BeginInvoke

的更多信息

示例:

        private void SessionRecords_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (e.NewItems?[0] != null)
            {
                Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(() =>
                {
                    recordListView.ScrollIntoView(e.NewItems[0]);
                }));
            };
        }

答案 1 :(得分:1)

您还可以使用async / await并执行类似的操作,这也应有助于避免过多的滚动(为简便起见,跳过了错误处理):

    private bool _pendingScroll = false;

    private async void SessionRecords_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        if (_pendingScroll) 
            return;

        _pendingScroll = true;
        try 
        {
            await System.Windows.Threading.Dispatcher.Yield(DispatcherPriority.ApplicationIdle);
            if (e.NewItems?[0] != null)
            {
                recordListView.ScrollIntoView(e.NewItems[0]);
            }
        }
        finally 
        {
            _pendingScroll = false;                        
        }
    }