исключение wpf listview argumentoutofrangeexception в mscorlib

#c# #wpf #listview #exception

#c# #wpf #listview #исключение

Вопрос:

У меня есть listview в простом приложении wpf, и оно выдает необработанное исключение:http://www.picz.ge/img/s2/1407/6/4/4d2baa8909d8.png

Необработанное исключение типа ‘System.Исключение ArgumentOutOfRangeException’ произошло в mscorlib.dll Дополнительная информация: Индекс был вне диапазона. Должно быть неотрицательным и меньше размера коллекции.

Я не могу понять, где ошибка. когда я устанавливаю time=2000; , код работает нормально; вот код:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Diagnostics;

namespace Wpftemp
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        Thread t;
        List<Something> listview_source;
        int time;
        public MainWindow()
        {
            InitializeComponent();
            listview_source = new List<Something>();
            listview.ItemsSource = listview_source;
            t = new Thread(f);
            time = 100;
            t.Start();
        }

        private void f()
        {
            while (true)
            {
                listview_source.Clear();
                refreshe_source();
                App.Current.Dispatcher.Invoke( delegate()
                {
                    listview.Items.Refresh();
                });
                Thread.Sleep(time);
            }
        }
        private void refreshe_source()
        {
            for (int i = 0; i < 150; i  )
            {
                 listview_source.Add(new Something(DateTime.Now.Second));
            }

        }

        struct Something
        {
           public Something(double i)
            {
                this.i = i;
            }
           double i;

           public double var
           {
               get { return i; }
               set { i = value; }
           }
        }
    }
}
  

Комментарии:

1. Каковы именно ваши намерения? поскольку все это выглядит как плохая идея.

2. Я хотел написать диспетчер задач

3. Хитрость с WPF заключается в том, чтобы НИКОГДА не касаться элемента управления в коде, вместо этого замените ваш List<T> на ObservableCollection<T> и привяжите его к вашему ListView , и просто добавьте и обновите ObservableCollection , и любые изменения будут показаны в пользовательском интерфейсе.

Ответ №1:

Я думаю, проблема в использовании диспетчера, потому что код внутри диспетчера.Invoke() будет выполнен после того, как основной поток будет готов к его выполнению, поэтому не гарантируется, когда именно код внутри Dispatcher.Вызов () будет выполнен, поэтому, когда вы увеличили значение time, вы гарантируете, что код был выполнен. Удалите диспетчер или увеличьте время значения.

Комментарии:

1. и как получить доступ к listview без диспетчера?

2. Вы можете получить к нему доступ непосредственно в главном потоке, но вы должны использовать диспетчер при доступе к нему из другого потока, вы можете использовать диспетчер при добавлении, обновлении и очистке элементов списка

3. @Wael — code inside dispatcher.Invoke() will be executed after the Main Thread is ready to execute it, so it is not guaranteed when exactly the code inside Dispatcher.Invoke() will be executed — Это утверждение совершенно неверно. Оно синхронно, поэтому будет выполнено перед любым предыдущим оператором. BeginInvoke является асинхронным, который выполняется, когда диспетчер получает время.

4.@RohitVats — Вы правы, диспетчер.Вызов () — это синхронная операция, НО синхронная операция только внутри основного потока, А не для всех потоков. listview_source.Clear(); // 1 refreshe_source(); //2 App.Current.Dispatcher.Invoke( delegate() { listview.Items.Refresh(); // 3 }); Thread.Sleep(time); //4 Я имею в виду, что оператор 4 может выполняться перед оператором 3, но если после оператора 3 и внутри метода Invoke() есть другой оператор (5), то оператор 5 ДОЛЖЕН выполняться после оператора 3.

5. Нет, это неправда. Инструкция 3 всегда будет выполняться первой перед инструкцией 4. Диспетчер пользовательского интерфейса выполнит все ожидающие операции и выполнит инструкцию 3, после чего управление будет передано инструкции 4. Вы можете попытаться напечатать что-то в UI dispatcher с помощью Invoke и что-то еще в инструкции 4, вы увидите, что инструкция 3 будет выполняться всегда.