2017-02-18 15 views
-4
using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Windows; 
using System.Windows.Input; 
using System.Windows.Media.Imaging; 

namespace IMDBWpf 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    /// 
    public partial class MainWindow : Window 
    { 
     private List<Movie> movieList; 
     BackgroundWorker bgWorker; 
     private string searchText; 

     public MainWindow() 
     { 
      InitializeComponent(); 

      bgWorker = new BackgroundWorker(); 
      bgWorker.DoWork += bgWorker_doWork; 
      bgWorker.RunWorkerCompleted += bgWorker_Completed; 
     } 

     private void bgWorker_Completed(object sender, RunWorkerCompletedEventArgs e) 
     { 
      Dispatcher.Invoke(() => 
      { 
       movieList = new Movies(searchText).movieList; 
       searchBar.ItemsSource = movieList; 
      }); 
     } 

     private void bgWorker_doWork(object sender, DoWorkEventArgs e) 
     { 
      Dispatcher.Invoke(() => 
      { 
       var loadingMovie = new Movie("src\\loader.gif", "Loading..."); 
       movieList = new List<Movie>(); 
       movieList.Add(loadingMovie); 
       searchBar.ItemsSource = movieList; 
       searchBar.IsDropDownOpen = true; 
      }); 
     } 

     private void searchBar_DataContextChanged(object sender, RoutedEventArgs e) 
     { 
      searchText = searchBar.Text; 

      if(!bgWorker.IsBusy) 
       bgWorker.RunWorkerAsync(); 
     } 
    } 
} 

У меня есть comboBox. Каждый элемент из combobox имеет метку и изображение.UserInterface зависает, когда работает BackgroundWorker

ComboBox заполнен элементами веб-страницы, процесс занимает некоторое время, пока это не будет выполнено.

Основная проблема заключается в том, что когда я пишу что-то в comboBox (да, это редактируется), мое приложение зависает, пока не будет создан список с элементами. Чтобы избавиться от этого замораживания, я попытался использовать BackgroundWorker, но он не работает ... Любые идеи почему? Я попытался использовать потоки в классе, который генерирует список, но ничего не происходит.

using HtmlAgilityPack; 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading; 
using System.Threading.Tasks; 

namespace IMDBWpf 
{ 
    struct Movie 
    { 
     public Movie(string movieImg, string movieT) 
     { 
      movieTitle = movieT; 
      movieImage = movieImg; 
     } 
     public string movieTitle { get; set; } 
     public string movieImage { get; set; } 
    } 

    class Movies 
    { 
     public List<Movie> movieList { get; set; } 
     public Movies(string movieName) 
     { 
      if (movieName.Length > 0) 
      { 
       populateList(movieName); 
      } 
     } 

     private void populateList(string movieName) 
     { 
      var webSite = new HtmlAgilityPack.HtmlWeb(); 
      var siteAddress = "http://www.imdb.com/find?ref_=nv_sr_fn&q=" + movieName + "&s=tt"; 
      HtmlDocument htmlPage = webSite.Load(siteAddress); 
      movieList = new List<Movie>(); 
      int index = 0; 

      while (htmlPage.DocumentNode.Descendants("td").ElementAt(index).Descendants("a").Any()) 
      { 
       var movie = new Movie(); 

       movie.movieImage = htmlPage.DocumentNode.Descendants("td").ElementAt(index++).Descendants("a").ElementAt(0).Descendants("img").ElementAt(0).GetAttributeValue("src", ""); 
       movie.movieTitle = htmlPage.DocumentNode.Descendants("td").ElementAt(index++).InnerText; 

       movieList.Add(movie); 
      } 
     } 
    } 
} 
+0

Я предполагаю, что 'searchbar' является' ComboBox'. – xoxox

+0

Что такое 'movieList' в' bgWorker_Completed'? – xoxox

+0

@xoxox Да, это ComboBox Я использую класс Movies для создания списка фильмов. Этот класс является причиной замораживания, и для этого мне нужен другой поток. – Marius

ответ

4

Есть некоторые проблемы с вашим дизайном. Фоновый рабочий вызывает bgWorker_dowork в отдельном потоке, но вся логика выполняется диспетчером, и, следовательно, логика все еще выполняется в потоке ui.

Я не могу найти, где в вашем коде тяжелая логика (это конструктор фильма?). Во всяком случае, переместите тяжелую логику вне метода лямбда invoke и просто зарегистрируйте его в поле со списком внутри.

+1

if (! bgWorker.IsBusy) bgWorker.RunWorkerAsync(); он звонит в случае –

+0

Ну, это невозможно ... Я хочу создать поисковую систему, такую ​​как google. Когда вы что-то пишете, он дает вам предложения. Поэтому мне нужно событие searchBar_DataContextChanged, вот почему мои два потока должны работать вместе. – Marius

0

Как указал Микаэль, понимание того, как работает BackgroundWorker.

Элементы управления пользовательского интерфейса (UserInterface) обрабатываются главным потоком (поток пользовательского интерфейса), но код внутри DoWork обрабатывается фоновым потоком.

Однако, если вы обернете весь код внутри DoWork с помощью Dispatcher.Invoke, BackgroundWorker больше не является BackgroundWorker.

Решение очень простое, что обертывание необходимых вещей с помощью Dispatcher.Invoke, как показано ниже.

private void bgWorker_doWork(object sender, DoWorkEventArgs e) 
{ 
    searchBar.Text= "src\\loader.gif", "Loading..."; 

    movieList = new Movies(searchText).movieList; 

    Dispatcher.Invoke(() => 
    { 
     searchBar.ItemsSource = movieList; 
     searchBar.IsDropDownOpen = true; 
    }); 
} 

private void bgWorker_Completed(object sender, RunWorkerCompletedEventArgs e) 
{ 
    if (e.Error != null) 
    { 
     Dispatcher.Invoke(() => 
     { 
      MessageBox.Show(e.Error.ToString()); 
     }); 
    }  
} 

управления пользовательского интерфейса являются такие, как COMBOBOX, TextBox, этикетки, сетки, StackPanel, кнопки и т.д.

BackgroundWorker действительно удобно, но немного понимания требуется в самом начале.

Поскольку код внутри DoWork был проинструктирован вами через поток Main (UI), ваше приложение должно быть заморожено, чтобы завершить выполняемую работу.

И вам не нужно повторять код в Completed, но лучше выполнять какую-либо другую необходимую работу или обрабатывать ошибку, если это произошло.

Обновление-

Я думаю, что одна из возможностей является то, что там могут быть некоторые проблемы при загрузке с сайта. Работа с веб-сайтами всегда асинхронна, поскольку время загрузки будет различным в зависимости от интернет-трафика. Но в это время, я думаю, у соединения может быть некоторая проблема, и поэтому ваша аппликация ждет до истечения времени по умолчанию веб-соединения.

+0

Где фильмList = новые фильмы (searchText) .movieList; ? Это линия, которая вызывает у меня проблемы – Marius

+0

Просто положите ее в подходящее место внутри DoWork. Точка замораживания может быть решена. И для вашей информации есть много уже готовых решений для таких функций, как поиск в Google на таких сайтах, как Github, Nuget.org, хотя вы уже знаете. –

+0

Немного путают во время моей работы. Я не знаю ваших точных кодов, но моя рекомендация обновлена ​​в моем ответе. –