WPF 数据绑定 ProgressBar

4
我正在制作一个WPF应用程序,在其中使用WebClient下载文件。我想在ProgressBar控件中显示ProgressPercentage。我在一个类中有一个方法,其中使用WebClient下载文件。我的问题是如何将ProgressBare.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"/>

进度条.Value = e.ProgressPercentage - Philippe Paré
我无法在另一个类中访问我的 ProgressBar?@PhilippeParé - Loc Dai Le
你可以创建一个事件(即“public event ProgressChangedEventHandler ProgressChanged”),并在每次DownloadProgressChanged触发时引发它。然后,你可以让进度条控制器订阅该事件。 - Dietz
谢谢您的回复@Dietz,但是您能否给出一个例子吗?我对WPF还很陌生。谢谢。 - Loc Dai Le
2个回答

6
为了一个简洁的解决方案,您需要一个ViewModel类,在其中创建一个StartDownload方法,您可以通过Command或在window中的button点击下调用它。
另一方面,有一个很好的Type类型名为IProgress。它作为我们的通知器工作,您可以像以下示例一样使用它 ;)
在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.csMyWindow.Xaml 中:

现在,您应该通过 Xaml 或 Code-Behind 将窗口 DataContext 填充为 DownloadViewModel 类的实例。

ProgressValue 属性绑定到 DownloadViewModel.cs 类:

<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!");

Result:

enter image description here


谢谢您的回答,@RAM。我将我的Datacontext设置为DownloadViewModel类,但进度条没有改变? - Loc Dai Le
抱歉,我在这里犯了一个小错误:_progressValue = d;。它必须是:ProgressValue = d;。为了更好的实现,我将ViewModel类中的public Progress property更改为简单的private member。现在,我已经更改了答案并进行了测试。它可以正常工作... - Ramin Bateni

0

你应该在你的方法中添加一个 IProgress<double> 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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接