【问题标题】:How do I program my progress bar in combination with asynchronous calls?如何结合异步调用对进度条进行编程?
【发布时间】:2013-06-23 15:31:36
【问题描述】:

首先,我的Windows Phone 8开发经验不是很丰富,但有些东西看起来像我比较熟悉的ASP.NET Framework。

我想要一个不确定的进度条,它在后台执行 Web 请求时显示,而在处理请求时隐藏。

我的解决方案有效,但我对它不满意
(progressBar/Text 位于一个枢轴元素内以测试功能)
我们有以下内容:

一个名为“MainPage”的 XAML 页面,带有 Pivot 元素。

<phone:PhoneApplicationPage>

...

    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <!-- HERE I want the progress bar and loading-text to show up if possible -->
            <TextBlock Name="ProgressText" Text="Loading..." Visibility="Collapsed"/>
            <ProgressBar Name="ProgressBar" Visibility="Collapsed" IsIndeterminate="True"/>
        <!-- HERE I want the progress bar and loading-text to show up if possible -->

        <phone:Pivot Title="MyTitle">
            <!-- Here are my PivotItems -->
        </phone:Pivot>

    </Grid>

<phone:PhoneApplicationPage>

我的代码隐藏如下所示:

protected override void OnNavigatedTo(
    App.ViewModel.LoadSomething();
}

函数 LoadSomething() 显示/隐藏进度条和加载文本。
这是我不满意的部分:

// Method of the ViewModel
public void LoadSomething()
{
    //Showing progress bar and loading-text
    var mainPage = (MainPage)App.RootFrame.Content;
    mainPage.ProgressBar.Visibility = Visibility.Visible;
    mainPage.ProgressText.Visibility = Visibility.Visible;

    // form the URI
    UriBuilder fullUri = new UriBuilder(string.Format("http://somepage..."));

    // initialize a new WebRequest
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(fullUri.Uri);

    // set up the state object for the async request
    UpdateState state = new UpdateState();
    state.AsyncRequest = request;

    // start the asynchronous request
    request.BeginGetResponse(
        new AsyncCallback(HandleResponse),
        state);
}

private void HandleResponse(IAsyncResult asyncResult)
{
    // Here happens logic and stuff


    Deployment.Current.Dispatcher.BeginInvoke(() =>
        {
            // Here happens logic and stuff

            //Hiding progress bar and loading-text
            var mainPage = (MainPage)App.RootFrame.Content;
            mainPage.ProgressBar.Visibility = Visibility.Collapsed;
            mainPage.ProgressText.Visibility = Visibility.Collapsed;
        });
}

现在我的问题是:

  1. 是否可以在我导航到的任何枢轴元素处显示进度条和加载文本?

  2. 如您所见,通过引用“(MainPage)App.RootFrame.Content”,我可以访问我的 Progress-Bar/Text 对象并简单地设置属性。但我不喜欢这种方式。
    我认为必须有一种方法可以使用 {Binding ...} 值设置进度条/文本,从而使代码更清晰。 因此,如何绑定 ProgressBar 和 ProgressText 的属性“Visibility”,使它们在 LoadSomething() 开始时变为“可见”,并在处理完成时变为“折叠”?

提前致谢!

亲切的问候

【问题讨论】:

    标签: c# xaml asynchronous windows-phone-8 progress-bar


    【解决方案1】:

    嗯,你几乎已经解决了,至少你描述了第二点的解决方案。

    1. 这很简单,只需将 TextBlock 和 ProgressBar 放在 xaml 中的 Pivot 下,以便它们呈现在 pivot 元素的顶部。然后,您可以使用 Horizo​​ntalAlignment、VerticalAlignment 和 Margin 排列它们。下面的代码应该把它们放在你的页面中间:

      <phone:PhoneApplicationPage>
      
      ...
      
      <Grid x:Name="LayoutRoot" Background="Transparent">
          <Grid.RowDefinitions>
              <RowDefinition Height="Auto"/>
              <RowDefinition Height="*"/>
          </Grid.RowDefinitions>
      
      
          <phone:Pivot Title="MyTitle">
              <!-- Here are my PivotItems -->
          </phone:Pivot>
      
          <!-- HERE I want the progress bar and loading-text to show up if possible -->
              <TextBlock Name="ProgressText" Text="Loading..." Visibility="Collapsed" VerticalAlignment="Center" HorizontalAlignment="Stretch"/>
              <ProgressBar Name="ProgressBar" Visibility="Collapsed" IsIndeterminate="True" VerticalAlignment="Center" HorizontalAlignment="Stretch"/>
          <!-- HERE I want the progress bar and loading-text to show up if possible -->
      </Grid>
      
      <phone:PhoneApplicationPage>
      
    2. 几乎一样简单。我怀疑您的 ViewModel 实现了 INotifyPropertyChanged 或从某个类派生?如果没有,那就这样做吧。 比将此属性添加到您的 ViewModel:

      private bool _IsLoading = false;
      
      public bool IsLoading
      {
          get { return _IsLoading; }
          set
          {
              if (_IsLoading != value)
              {
                  _IsLoading = value;
                  NotifyPropertyChanged("IsLoading");
              }
          }
      }
      

      (NotifyPropertyChanged 是您的版本:

      public event PropertyChangedEventHandler PropertyChanged;
      public void NotifyPropertyChanged(String name)
      {
          PropertyChangedEventHandler handler = PropertyChanged;
          if (handler != null)
              handler(this, new PropertyChangedEventArgs(name));
      }
      

    如果您还没有 BooleanToVisibilityConverter,请添加此类以将布尔值转换为 xaml 中的可见性:

    public class BooleanToVisibilityConverter : IValueConverter
    {
    
    
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return (value is bool && (bool)value) ? Visibility.Visible : Visibility.Collapsed;
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return value is Visibility && (Visibility)value == Visibility.Visible;
        }
    }
    

    在创建 MainPage 时,您将整个页面或 TextBlock 和 ProgressBar 的 DataContext 设置为您的 ViewModel(或者您通过 Resources 和 xaml 进行设置,但这没关系),将 BooleanToVisibilityConverter 添加为 Page像这样的资源:

    <phone:PhoneApplicationPage.Resources>
         <local:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
    </phone:PhoneApplicationpage.Resources>
    

    并将 TextBlock 和 ProgressBar 的可见性属性绑定到 ViewModel 的 IsLoading 属性:

    <TextBlock Name="ProgressText" Text="Loading..." Visibility="{Binding IsLoading, Converter={StaticResource BooleanToVisibilityConverter}}" VerticalAlignment="Center" HorizontalAlignment="Stretch"/>
    <ProgressBar Name="ProgressBar" Visibility="{Binding IsLoading, Converter={StaticResource BooleanToVisibilityConverter}}" IsIndeterminate="True" VerticalAlignment="Center" HorizontalAlignment="Stretch"/>
    

    最后一件事:

    在 LoadSomething() 的开头设置 IsLoading = true; 并在 HandleResponse 方法的末尾设置 IsLoading = false; 应该这样做。

    【讨论】:

    • 谢谢,这完全使它起作用了 :) 我有 IValueConverter 的章节,但我只是忘记了如何将它与 INotifyPropertyChanged 对象的属性结合使用。
    猜你喜欢
    • 1970-01-01
    • 2018-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-19
    相关资源
    最近更新 更多