C # RSS feed reader с потоком, каналы записываются в ListView несколько раз

#c# #multithreading #listview #delegates

#c# #многопоточность #просмотр списка #делегаты

Вопрос:

У меня есть программа чтения новостей RSS, которая считывает rss-канал и записывает новости со ссылками в ListView. когда я выполняю свою программу, я запускаю новый поток, подобный этому:

     Thread myThread = new Thread(getNews);
    myThread.Start();
  

Мой метод чтения канала выглядит следующим образом:

     public void getNews()
    {  
        //Creates a XmlTextReader which reads from the url entered in input field
        rssReader = new XmlTextReader(txtUrl.Text);

        //Creates an xml doc to save the content of the entered path
        rssDoc = new XmlDocument();

        //Loads the xml content from the reader into a XmlDocument
        rssDoc.Load(rssReader);

        //Make a loop to search for the <rss> tag
        for (int i = 0; i < rssDoc.ChildNodes.Count; i  )
        {
            //If the childenode is the rss tag
            if (rssDoc.ChildNodes[i].Name == "rss")
            {
                //the <rss> tag is found, and we know where it is
                nodeRss = rssDoc.ChildNodes[i];
            }
        }

        //Make a loop to search for the <channel> tag
        for (int i = 0; i < nodeRss.ChildNodes.Count; i  )
        {
            //If the childnode is the channel tag
            if (nodeRss.ChildNodes[i].Name == "channel")
            {
                //The channel tag is found and we know where it is
                nodeChannel = nodeRss.ChildNodes[i];
            }
        }

        //Make a loop to search for the <item> tag
        for (int i = 0; i < nodeChannel.ChildNodes.Count; i  )
        {
            //If the childnode is the item tag
            if (nodeChannel.ChildNodes[i].Name == "item")
            {
                //the item tag is found, and we know where it is
                nodeItem = nodeChannel.ChildNodes[i];

                //Creates a new row in the LstView which contains information from inside the nodes
                rowNews = new ListViewItem();
                rowNews.Text = nodeItem["title"].InnerText;
                rowNews.SubItems.Add(nodeItem["link"].InnerText);

                if (this.lstView.InvokeRequired)
                {
                    AddItemCallback d = new AddItemCallback(getNews);
                    this.Invoke(d);
                }
                else
                {
                    lstView.Items.Add(rowNews);
                }
            }

        }
  

Моя проблема в том, что после того, как я начал запускать свой код в новом потоке и использовать делегат для проверки, запрашивает ли ListView вызов, все новостные ленты записываются в мой ListView несколько раз. если я запускаю метод без запуска нового потока и использую делегат, он записывается только один раз, почему это? Вероятно, это очень простой вопрос, но я просто не могу понять, почему

Заранее спасибо, примеры кода приветствуются 🙂

Ответ №1:

Вы установили проверку вызова в неправильном месте — таким образом, ваша функция getNews вызывается намного, намного больше раз, чем вы предполагали.

в самом верху getNews попробуйте следующее:

 if (this.lstView.InvokeRequired) {
AddItemCallback d = new AddItemCallback(getNews);
this.Invoke(d);
return;
}
  

Затем замените оператор if в конце на lstView.Items.Add(rowNews);

Конечно, выполнение этого таким образом эффективно перенаправляет ваши getNews в поток пользовательского интерфейса. Что вам действительно нужно, так это создать коллекцию элементов ListViewItems и передать эту коллекцию методу обновления .. и в ЭТОМ методе вы проверяете, требуется ли вызов.

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

1. Хм, да, кажется, работает, но приложения действуют так, как будто я не использую поток, поэтому при поиске новостной ленты я не могу с ней взаимодействовать. Можете ли вы привести пример того, что вы подразумеваете под созданием метода обновления?

Ответ №2:

Если требуется invoke, вы снова вызываете метод getNews. Вместо использования этого кода:

 if (this.lstView.InvokeRequired)
{
     AddItemCallback d = new AddItemCallback(getNews); // STOP CALLING getNews
     this.Invoke(d);
}
  

Вам нужно вызвать другой метод для обновления вашего пользовательского интерфейса. Это гигантский цикл.