【问题标题】:How to download content and update UI in Wpf?如何在 Wpf 中下载内容和更新 UI?
【发布时间】:2016-06-17 18:10:42
【问题描述】:

我在使用 ui 更新从服务器下载多个图像时遇到问题。问题是我在服务器上有墙纸文件夹并且我想下载图像,我运行后台工作程序来下载图像并更新我的 UI,一旦我的所有图像下载完成(BackgroundWorker_Completed),我的 UI 更新就会完成。但我希望每次下载一个图像文件夹时更新我的​​ UI,如下图所示。

在上面给出的示例中,每个文件夹都包含多个图像,例如电影、游戏、印度等,并且它们具有所属类别的图像,例如在电影中,它们是文件夹,比如钢铁侠、牧师等。现在,当我下载我的图像时,它们应该在 UI 上可见,每次下载都不是最后一次。下载壁纸代码如下:


下载图片的后台工作代码

  void worker_DoWork(object sender, DoWorkEventArgs e)
            {
                try
                {
                    DataSet dsFile = Global.ReadConfig;

                    XDocument xDoc = XDocument.Load(dsFile.Tables[0].Rows[0][8].ToString());
                    string s = xDoc.Root.Name.ToString();
                    var countNode = xDoc.Root.Elements().Count();
                    for (int i = 0; i < countNode; i++)
                    {
                        XNode childNode = xDoc.Root.Nodes().ElementAt(i);
                        XElement ele = (XElement)childNode;
                        string path = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "\\Wallpaper\\" + ele.Name;

                        var movieList = from a in xDoc.Root.Descendants(ele.Name).Elements()
                                        select a;
                        foreach (var a in movieList)
                        {
                            string newpath = path + "\\" + a.Value;
                            DirectoryInfo di = new DirectoryInfo(newpath);
                            if (!di.Exists)
                            {
                                DirectoryInfo dinew = Directory.CreateDirectory(newpath);
                                filedownload(dsFile.Tables[0].Rows[0][1].ToString() + "/Wallpaper/" + ele.Name + "/" + dinew.Name + "/", newpath + "\\");   
                            }
                        }
                        //new DesktopThemes.App_Page.MainWindow().getWallLink(ele.Name.LocalName);
                    }
                }
                catch
                {

                }

            }

后台工作人员已完成以在 UI 上显示图像

void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            string N = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + @"\Wallpaper\" ;

            Random random = new Random();

            List<String> backimage = new List<String>();

            DirectoryInfo diback = new DirectoryInfo(N);
            // diback.GetFiles();

            Directory.GetFiles(N, "*.*", SearchOption.AllDirectories);

            foreach (var imagename in diback.GetFiles("*.jpg", SearchOption.AllDirectories))
            {
                backimage.Add(imagename.Directory + "\\" + imagename.Name);
            }
            try
            {
                Image image = new Image();
                Uri add = new Uri(backimage[random.Next(0, backimage.Count - 1)]);
                image.Source = new BitmapImage(add);

                pnlBackground.Source = image.Source;
                this.Photos.Path = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + @"Wallpaper\";
            }
            catch (Exception ex)
            {

            }
        }

后台工作人员调用的图片下载代码

    public static void filedownload(String url, string downloadlocation)
        {
            FtpWebRequest ftpRequest = (FtpWebRequest)WebRequest.Create(url);
            ftpRequest.Credentials = new NetworkCredential(@username, @password);
            ftpRequest.Method = WebRequestMethods.Ftp.ListDirectory;
            FtpWebResponse response = (FtpWebResponse)ftpRequest.GetResponse();

            StreamReader streamReader = new StreamReader(response.GetResponseStream());
            List<string> directories = new List<string>();
            string line = streamReader.ReadLine();
            while (!string.IsNullOrEmpty(line))
            {
                directories.Add(line);
                line = streamReader.ReadLine();
            }
            streamReader.Close();
            using (WebClient ftpClient = new WebClient())
            {
                ftpClient.Credentials = new System.Net.NetworkCredential(@username, @password);
                for (int i = 0; i <= directories.Count - 1; i++)
                {
                    if (directories[i].Contains("."))
                    {
                        string path = url + directories[i].ToString();
                        string trnsfrpth = downloadlocation + directories[i].ToString();                            if (!new System.IO.FileInfo(trnsfrpth).Exists)
                        {
                            ftpClient.DownloadFile(path, trnsfrpth);
                        }
                    }
                }
            }
        }

【问题讨论】:

  • 请提供额外的 XAML 代码。看来您的绑定没有更新,但如果没有 XAML 就很难分辨
  • @lok​​usking pnlBackground.Source = image.Source; 暗示没有绑定。
  • 主要问题是您在 RunWorkerCompleted 处理程序中一次创建所有 BitmapImages。另一种方法是在下载后立即创建每个 BitmapImage(在 DoWork 中)。您必须确保在创建期间设置BitmapCacheOption.OnLoad 标志并调用Freeze() 方法以使其可跨线程访问。将位图分配给图像控件必须在 UI 线程中完成,例如Dispatcher.Invoke()。除此之外,为pnlBackground.Source = image.Source 提供中间图像控件是完全多余的。
  • 我建议有一个ObservableCollection&lt;ImageSource&gt;(通过 Dispatcher 调用更新),并将 ListBox 绑定到该集合。然后在 ListBox 的 ItemTemplate 中声明一个 Image 控件,并将其 Source 属性绑定到集合元素,如&lt;Image Source="{Binding}" /&gt;

标签: c# wpf


【解决方案1】:

要了解如何异步下载大量图像同时在 ListBox 中显示它们,请查看以下简化视图模型,它声明了所有下载图像的集合属性和 async执行下载的方法。

下载是异步的,因为该方法调用(并等待)异步HttpClient.GetByteArrayAsync() 方法。

为了演示,它从openstreetmap.org下载了256张(地图瓦片)图像。

public class ViewModel
{
    public ObservableCollection<ImageSource> Images { get; private set; }
        = new ObservableCollection<ImageSource>();

    public async Task DownloadImages()
    {
        var httpClient = new HttpClient();

        for (int y = 0; y < 16; y++)
        {
            for (int x = 0; x < 16; x++)
            {
                var url = string.Format(
                    "http://tile.openstreetmap.org/4/{0}/{1}.png", x, y);

                // the await here makes the download asynchronous
                var buffer = await httpClient.GetByteArrayAsync(url);

                using (var stream = new MemoryStream(buffer))
                {
                    Images.Add(BitmapFrame.Create(
                        stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad));
                }
            }
        }
    }
}

您可以设置 MainWindow 的 DataContext 并在 Loaded 事件处理程序中开始下载,如下所示:

public MainWindow()
{
    InitializeComponent();

    var viewModel = new ViewModel();
    DataContext = viewModel;

    Loaded += async (s, e) => await viewModel.DownloadImages();
}

最后,ListBox 的 XAML 可能如下所示:

<ListBox ItemsSource="{Binding Images}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Image Source="{Binding}" />
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多