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充满了来自网页的元素,这个过程需要一些时间才能完成。
主要的问题是,当我在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 :(得分:4)
您的设计存在一些问题。后台工作程序在一个单独的线程中调用bgWorker_dowork,但所有逻辑都由调度程序执行,因此逻辑仍然在ui线程中执行。
我无法在你的代码中找到重逻辑的位置(它是Movie构造函数吗?)。无论如何,将重逻辑移到invoke lambda方法之外,然后将其注册到里面的组合框中。
答案 1 :(得分:0)
像Micael指出的那样,需要了解BackgroundWorker的工作原理。
UI(UserInterface)控件由主线程(UI线程)处理,但DoWork内的代码由后台线程处理。
但是,如果使用Dispatcher.Invoke将所有代码包装在DoWork中,则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());
});
}
}
UI控件如comboBox,textBox,label,Grid,StackPanel,Button等。
BackgroundWorker非常方便,但一开始就需要了解一点。
由于DoWork中的代码是由您通过Main(UI)线程完成的,因此必须冻结您的应用程序以完成指示的工作。
您不需要在Completed中重复代码,但最好还是做一些其他必要的工作或处理错误(如果发生)。
更新 -
我认为可能的一种可能性是从网站下载时可能存在一些问题。 使用网站始终是异步的,意味着加载时间会因互联网流量而异。但是在这个时候,我猜连接可能有一些问题,因此,你的应用程序正在等待网络连接的默认超时。