【问题标题】:WPF MVVM Thread keep running and show progress in wpf windowsWPF MVVM 线程继续运行并在 wpf 窗口中显示进度
【发布时间】:2015-09-20 15:05:55
【问题描述】:

现在我正在 WPF MVVM 中开发后台下载应用程序。当应用程序启动时,下载线程开始工作。我想在每个 WPF 窗口的标签框中显示下载状态,以了解已下载的百分比。

我已经尝试过BackgroundWorker。我使用HttpClient下载文件,下载过程写在DoWork函数下。

如何从每个 WPF 窗口获取下载进度以显示在标签框中?

欢迎提出任何建议。

最佳 Rgds, 箭蛙

【问题讨论】:

  • 虽然 backgroundworker 没问题,但您可能想使用其他一些方法来实现异步,即Task
  • 你的意思是DoWork函数中的Task进程吗?
  • 如何从每个 WPF 窗口获取下载进度以显示在标签框中?他们的多个窗口和一个带有标签的父窗口是否可以查看下载状态?或者在同一个窗口中有多个下载任务。同样的窗口也包含标签。请澄清。
  • 导致下载线程一直运行直到应用程序退出。我想展示不同的窗户有不同的风格。这就是为什么

标签: c# wpf mvvm


【解决方案1】:

您可以使用BackgroundWorkerTask 来实现此目的。 @razor118 说的是真的;下载服务应该是单例的,或者最好注入到您的 ViewModel 中,并且在这里公开事件是您所需要的。

这是(工作但远未完成)示例,使用Tasks 和EventHandler 来“通知”两个单独的Windows 下载进度。


App.xaml

// where util is xmlns:util="clr-namespace:WpfApplication1.Util"
// Make file downloader a application level resource
<Application.Resources>
    <util:Downloader x:Key="MyDownloader" />
</Application.Resources>

MainWindow.xaml

<Window.DataContext>
    <!-- MainView's data context -->
    <viewModel:MainViewModel />
</Window.DataContext>

<!-- Label to show download progress -->
<Label Content="{Binding Progress}">
    <Label.ContentStringFormat>{0}%</Label.ContentStringFormat>
</Label>

MainWindow.cs

public partial class MainWindow : Window
{
    public MainWindow()
    {
        // Nothing to do here
        InitializeComponent();
    }
}

MainViewModel.cs

public class MainViewModel : ViewModelBase
{
    private int _progress;

    public MainViewModel()
    {
        // Open new window beside Main
        var otherView = new OtherWindow();
        otherView.Show();

        // Get downloader resource
        var downloader = Application.Current.Resources["MyDownloader"] as Downloader;
        // Update property when ever download progress changes (event)
        downloader.DownloadProgressChanged += (sender, args) => 
            Progress = args.ProgressPercentage;
        // Start downloading a 10Mb file
        downloader.Get("http://mirror.internode.on.net/pub/test/10meg.test");
    }

    public int Progress
    {
        get { return _progress; }
        private set { _progress = value; RaisePropertyChanged();}
    }
}

OtherWindow.xaml(无支持 ViewModel)

<!-- Label to show download progress -->
<Label x:Name="ProgressLabel"></Label>

OtherWindow.cs

public partial class OtherWindow : Window
{
    public OtherWindow()
    {
        InitializeComponent();

        // Get downloader resource
        var downloader = Application.Current.Resources["MyDownloader"] as Downloader;
        // Update label when ever download progress changes (event)
        downloader.DownloadProgressChanged += (sender, args) => 
            ProgressLabel.Content = string.Format("{0}%", args.ProgressPercentage);
    }
}

Downloader.cs

public class Downloader // in WpfApplication.Util namespace
{
    public event EventHandler<DownloadProgressChangedEventArgs> DownloadProgressChanged;

    // Download a file
    public async void Get(string url)
    {
        Uri uri = new Uri(url);
        using (WebClient webClient = new WebClient())
        {
            webClient.DownloadProgressChanged += (sender, args) => OnProgressChanged(args);
            await webClient.DownloadDataTaskAsync(uri);
        }
    }

    // Notify when progress changes
    private void OnProgressChanged(DownloadProgressChangedEventArgs e)
    {
        var handler = DownloadProgressChanged;
        if (handler != null)
            DownloadProgressChanged(this, e);
    }
}

【讨论】:

  • 嗨,兄弟,我的下载过程返回用户 ID 和下载百分比。我得到了 datagridview 并填充了用户列表。我如何显示按用户 ID 过滤的特定行下载过程。我的下载是一次一个。
  • 也许您应该就此提出另一个问题。使用您的代码。
【解决方案2】:

我认为最好的方法是为这个特定任务 (FileFetcher.cs) 编写自定义类,该类将在后台线程中运行任务。这应该被注入或者是一个单例。类可以公开一个事件,例如:StatusChanged(例如“下载 2 个文件 50%”的消息)。

每个视图都可以注册该事件并在 UIThread 上调度后更新窗口标签。

【讨论】:

  • 感谢您的回答,razor118。你得到任何示例链接或源代码吗?因为我很菜鸟。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-19
  • 1970-01-01
  • 2010-12-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多