【问题标题】:Bind a progress bar value with the value of a property given by an API将进度条值与 API 提供的属性值绑定
【发布时间】:2019-07-15 21:01:51
【问题描述】:

我想更新 WPF 表单中进度条的值,以指示一组任务的进度。

这些任务由 dll 中提供的 API 执行。 API 提供有关任务总数和已完成任务数的信息。

我已将进度条的值与我的主类中的一个属性绑定,但我无法显示任务执行过程中的进度,只能显示 0% 和 100% 的进度。

MyForm.xaml.cs

   public partial class MyForm : Page, INotifyPropertyChanged
   {
      public int PercentageOfTasksCompleted
      {
         get
         {
            int percentage_completed = 100 * externalAPI.NumberOfTasksCompleted / externalAPI.TotalNumberOfTasks;

            return percentage_completed;
         }
         set
         {
            if (PropertyChanged != null)
            {
               PropertyChanged(this, new PropertyChangedEventArgs("PercentageOfTasksCompleted"));
            }
         }
      }

      private async void ButtonExecuteTasks_ClickAsync(object sender, RoutedEventArgs e)
      {
         await Task.Run(() =>
         {
            externalAPI.ExecuteTasks();
         });
      }
   }

MyForm.xaml

<Grid HorizontalAlignment="Left" VerticalAlignment="Bottom" Height="20" Width="200">
    <ProgressBar x:Name="myProgressBar" Value="{Binding PercentageOfTasksCompleted, Mode=OneWay}" Minimum="0" Maximum="100"/>
    <TextBlock Text="{Binding ElementName=myProgressBar, Path=Value, StringFormat={}{0:0}%}" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>

至于重现场景,我认为外部 API 类可能如下所示:

ExternalAPI.cs

   public class ExternalAPI
   {
      public int TotalNumberOfTasks {get; private set;}
      public int NumberOfTasksCompleted {get; private set;}

      public void ExecuteTasks() {
         for (int i=1; i<=TotalNumberOfTasks; i++)
         {
            Thread.Sleep(100);
            NumberOfTasksCompleted = i;
         }
      }
   }

在执行任务期间更新进度条值的最佳方法是什么?谢谢!

【问题讨论】:

  • 这是 Xamarin 还是 WPF?您在问题中写了“Xamarin”,但标记为 WPF。你在哪里设置PercentageOfTasksCompleted 属性? Xamarin 是否要求您显式处理绑定属性的跨线程封送处理?其他基于 XAML 的 API 没有(WPF、UWP),但 Xamarin 可能有。目前,您的问题质量不足,无法提供良好的答案。请改进它,包括添加一个好的minimal reproducible example 以可靠地重现问题。
  • @PeterDuniho 这是 WPF 抱歉,我已经更正了文本。我不知道在哪里设置PercentageOfTasksCompleted。我从 API 获得的唯一信息是 TotalNumberOfTasks 和 NumberOfTasksCompleted。一旦我打电话给externalAPI.ExecuteTasks(),我知道进度的唯一方法就是检查externalAPI.NumberOfTasksCompleted。至于最小的工作示例,我认为可以是:public void ExecuteTasks() { for (int i=1; i&lt;=TotalNumberOfTasks; i++) { Thread.Sleep(100); NumberOfTasksCompleted = i; } }
  • “一旦我调用 externalAPI.ExecuteTasks() 是我知道它检查 externalAPI.NumberOfTasksCompleted 进度的唯一方法” - 那么你将不得不定期这样做在任务执行时。

标签: c# wpf xaml progress-bar


【解决方案1】:

我改变了get和set如下:

MyForm.xaml.cs

   public partial class MyForm : Page, INotifyPropertyChanged
   {
      private int _percentage_completed = 0;
      public int PercentageOfTasksCompleted
      {
         get
         {
            return _percentage_completed;
         }
         set
         {
            _percentage_completed = value;

            if (PropertyChanged != null)
            {
               PropertyChanged(this, new PropertyChangedEventArgs("PercentageOfTasksCompleted"));
            }
         }
      }

设置 PercentageOfTasksCompleted 值:

while (externalAPI.NumberOfTasksCompleted < externalAPI.TotalNumberOfTasks)
{
   PercentageOfTasksCompleted = 100 * externalAPI.NumberOfTasksCompleted / externalAPI.TotalNumberOfTasks;
   Thread.Sleep(100);
}

使用此解决方案,进度条值会以指定的时间间隔更新,但我想知道是否有更“无缝”的方法。

【讨论】:

    【解决方案2】:

    所以你看到的是对变量类型的疏忽。 假设你总共有 10 个任务。当完成的任务低于 10 时,你总是得到零(0),为什么?因为你将两个整数相除。当它达到 10 时,你得到 100%。 您只需要将一个整数转换为浮点数,然后再转换回整数,使用var 进行变量定义也是一个好习惯:

        var percentage_completed = 100 * (int)((float )externalAPI.NumberOfTasksCompleted / externalAPI.TotalNumberOfTasks);
    

    【讨论】:

    • 该问题与设置变量 percent_completed 有关,因此它可以触发进度条刷新。类型之间的转换按预期执行,因为 externalAPI.NumberOfTasksCompleted 在除以 externalAPI.TotalNumberOfTasks 之前乘以 100。在您的解决方案中,由于您对操作进行分组的方式,首先执行除法,这导致 0 成为操作数,直到除数和除数相等,在这种情况下它变为 1。
    猜你喜欢
    • 2020-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-09
    • 1970-01-01
    • 2011-12-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多