How to use progressbar in an async webclient call

2019-07-14 03:04发布

问题:

I am trying to use performance progressbar in a WP7 project but I have trouble with the async webclient call. My code is as follows:

Update

    public MainPage()
    {
        InitializeComponent();
         ...................

        this.Loaded += new RoutedEventHandler(MainPage_Loaded);}

    private void MainPage_Loaded(object sender, RoutedEventArgs e)
    {
        if (!App.ViewModel.IsDataLoaded)
        {
            App.ViewModel.LoadData();
        }
    }

And the ViewModel where I implement the LoadData function

    private bool _showProgressBar = false;
    public bool ShowProgressBar
    {
        get { return _showProgressBar; }
        set
        {
            if (_showProgressBar != value)
            {
                _showProgressBar = value;
                NotifyPropertyChanged("ShowProgressBar");
            }
        }
    public void LoadData()
    {
        try
        {
            string defaulturl = "http://....";
            WebClient client = new WebClient();
            Uri uri = new Uri(defaulturl);
            client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
            ShowProgressBar = true;
            client.DownloadStringAsync(uri);
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }

        this.IsDataLoaded = true;

    }

    void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
    {
        try
        {
            //fetch the data
           ShowProgressBar = false;
        }

        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }

    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(String propertyName)
    {.....
    } 

MainPage Xaml

    <toolkit:PerformanceProgressBar Margin="0,-12,0,0" x:Name="performanceProgressBar" IsIndeterminate="true" Visibility="{Binding ShowProgressBar, Converter={StaticResource BooleanToVisibilityConverter}}"/>

My problem is that because the WebClient is an async method when it is executed, the LoadData has already been executed and I can't figure out where to place the performanceProgressBar.Visibility

Any help would be appreciated. Thanks!

回答1:

After you explained more in your comments, I understand more. Sounds like you want to bind a boolean property to the visibility of your progress bar. You'll need a boolean-to-visbility converter (google it, it's easy to find).

Then you can do something like this:

private bool _showProgressBar = false;
public bool ShowProgressBar
{
    get { _return _showProgressBar; }
    set 
    { 
        _return _showProgressBar;
        OnPropertyChanged("ShowProgressBar");
    }
}

public void LoadData()
{
    try
    {
        string defaulturl = "http://....";
        WebClient client = new WebClient();
        Uri uri = new Uri(defaulturl);
        client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted);

        ShowProgressBar = true;

        client.DownloadStringAsync(uri);
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }

    this.IsDataLoaded = true;

}

void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
    try
    {
        //fetch the data
        ShowProgressBar = false;
    }

    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }

}

On the View:

<MyProgressBar Visibility={Binding Path=ShowProgressBar, Converter={StaticResource MyBoolToVisibleConverter}>

Apparently, MSFT offers a converter for you already...this is news to me: http://msdn.microsoft.com/en-us/library/system.windows.controls.booleantovisibilityconverter.aspx



回答2:

You just need to get back on the UI thread -- the Dispatcher can help you out, and a common snippet I use (in my ViewModelBase is:

    protected delegate void OnUIThreadDelegate();
    /// <summary>
    /// Allows the specified deelgate to be performed on the UI thread.
    /// </summary>
    /// <param name="onUIThreadDelegate">The delegate to be executed on the UI thread.</param>
    protected void OnUIThread(OnUIThreadDelegate onUIThreadDelegate)
    {
        if (Deployment.Current.Dispatcher.CheckAccess())
        {
            onUIThreadDelegate();
        }
        else
        {
            Deployment.Current.Dispatcher.BeginInvoke(onUIThreadDelegate);
        }
    }

This can then be used simply with:

void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
    try
    {
        //fetch the data

        this.OnUIThread(() =>
        {
            performanceProgressBar.Visibility = Visibility.Collapsed; // This code will be performed on the UI thread -- in your case, you can update your progress bar etc.
        });

    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }

}