【问题标题】:WPF databinding ProgressBarWPF 数据绑定进度条
【发布时间】:2015-08-21 18:48:55
【问题描述】:

我正在制作一个 WPF 应用程序,我使用WebClient 下载文件。我想在ProgressBar 控制器中显示ProgressPercentage。我在使用WebClient 下载文件的类中有一个方法。我的问题是如何将ProgressBar 数据绑定到e.ProgressPercentage

类中的方法(DownloadFile):

public async Task DownloadProtocol(string address, string location)
{

        Uri Uri = new Uri(address);
        using (WebClient client = new WebClient())
        {
            //client.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
            //client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgress);
            client.DownloadProgressChanged += (o, e) =>
            {
                Console.WriteLine(e.BytesReceived + " " + e.ProgressPercentage);
                //ProgressBar = e.ProgressPercentage???
            };

            client.DownloadFileCompleted += (o, e) =>
            {
                if (e.Cancelled == true)
                {
                    Console.WriteLine("Download has been canceled.");
                }
                else
                {

                    Console.WriteLine("Download completed!");
                }

            };

            await client.DownloadFileTaskAsync(Uri, location);
        }

}

进度条:

<ProgressBar HorizontalAlignment="Left" Height="24" Margin="130,127,0,0" VerticalAlignment="Top" Width="249"/>

【问题讨论】:

  • ProgressBar.Value = e.ProgressPercentage ?
  • 我无法在其他班级访问我的 ProgressBar? @PhilippeParé
  • 您可以创建一个偶数(即“公共事件 ProgressChangedEventHandler ProgressChanged”),并在每次 DownloadProgressChanged 触发时引发它。然后让进度条控制器订阅该事件。
  • 感谢您的回复@Dietz,但您不能举个例子吗?我对 WPF 很陌生。谢谢。

标签: c# wpf data-binding progress-bar


【解决方案1】:

对于一个干净的解决方案,您需要一个ViewModel 类,我们在其中创建一个StartDownload 方法,您可以通过Command 或在button 下单击window 来调用它。

另一方面,有一个很好的Type,名为IProgress&lt;T&gt;。它可以作为我们的informer,您可以像下面的示例一样使用它;)


在 DownloadViewModel.cs 内:

public sealed class DownloadViewModel : INotifyPropertyChanged
{
    private readonly IProgress<double> _progress;
    private double _progressValue;

    public double ProgressValue
    {
        get
        {
            return _progressValue;
        }
        set
        {
            _progressValue = value;
            OnPropertyChanged();
        }
    }

    public DownloadViewModel()
    {
        _progress = new Progress<double>(ProgressValueChanged);
    }

    private void ProgressValueChanged(double d)
    {
        ProgressValue = d;
    }

    public async void StartDownload(string address, string location)
    {
        await new MyDlClass().DownloadProtocol(_progress, address, location);
    }

    //-----------------------------------------------------------------------
    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

在 MyDlClass 中。 cs

public class MyDlClass
{
    public async Task DownloadProtocol(IProgress<double> progress, string address, string location)
    {

        Uri Uri = new Uri(address);
        using (WebClient client = new WebClient())
        {
            //client.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
            //client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgress);
            client.DownloadProgressChanged += (o, e) =>
            {
                Console.WriteLine(e.BytesReceived + " " + e.ProgressPercentage);
                progress.Report(e.ProgressPercentage);
            };

            client.DownloadFileCompleted += (o, e) =>
            {
                if (e.Cancelled == true)
                {
                    Console.WriteLine("Download has been canceled.");
                }
                else
                {

                    Console.WriteLine("Download completed!");
                }

            };

            await client.DownloadFileTaskAsync(Uri, location);
        }

    }
}

内部MyWindow.Xaml.cs & MyWindow.Xaml

现在您应该使用 DownloadViewModel 类的实例(通过 Xaml 或 Code-Behind)填充您的窗口 DataContext

绑定到DownloadViewModel.cs 类的ProgressValue 属性:

<ProgressBar HorizontalAlignment="Left" Height="24" Margin="130,127,0,0" VerticalAlignment="Top" Width="249"
             Minimum="0"
             Maximum="100"
             Value="{Binding Path=ProgressValue}"/>

最后,在你的按钮 OnClick 中写下:

if(this.DataContext!=null)
   ((DownloadViewModel)this.DataContext).StartDownload("__@Address__","__@Location__");
else
    MessageBox.Show("DataContext is Null!");

结果:

【讨论】:

  • 感谢您的回答@RAM。我坐在我的 Datacontext = DownloadViewModel 类,但进度条没有改变?
  • 对不起,我在这里有点错误:_progressValue = d; 必须是:ProgressValue = d;。同样为了更好的实现,我将public Progress property 更改为ViewModel 类中的简单private member。现在我改变了答案并自己测试了它。它有效...
【解决方案2】:

您应该在您的方法中添加一个IProgress&lt;double&gt; progress 参数,只要您的客户想要更新进度然后调用progress.Report()IProgress 在您的视图/窗口一侧将指向一个方法,您将在其中实现 MyProgressBar.Value = value 或其他任何内容。

使用IProgress 有效地消除了与将提供更新的目标控件的交互,此外它还负责调用调度程序,因此您不会遇到通常的无效跨线程调用错误。

请参阅此帖子以获取示例:

http://blogs.msdn.com/b/dotnet/archive/2012/06/06/async-in-4-5-enabling-progress-and-cancellation-in-async-apis.aspx

【讨论】:

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