【问题标题】:ListView with a progress bar populated by Model property带有由 Model 属性填充的进度条的 ListView
【发布时间】:2019-07-11 06:20:30
【问题描述】:

亲爱的,

我想创建一个包含一些模型信息的列表视图,使用 INotifyPropertyChanged 来实时填充和更新我的信息。但是当我尝试在我的 Progress 函数中使用绑定时,它不起作用。

我的看法是:

   <?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:skia="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
             x:Class="H2XA.View.PatientView"
             Title="Pacientes">

        <StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">

            <Label x:Name="Paciente1" Text="Paciente"
                   HorizontalOptions="Center"
                   VerticalOptions="Center"
                    />  
              <ListView x:Name="Patients" 
                          ItemSelected="OnSelection"
                          IsPullToRefreshEnabled="True">
                    <ListView.ItemTemplate>
                        <DataTemplate>
                            <ViewCell>
                                <ViewCell.ContextActions>
                                    <MenuItem Text="Renomear" CommandParameter="{Binding .}"
                                         Clicked="Renomear_Clicked" />
                                </ViewCell.ContextActions>
                                <StackLayout Padding="5,0,5,0">
                                    <Label Text="{Binding Name}" Font="16"/>
                                    <Label Text="{Binding Medidas}" Font="14" />
                                    <ProgressBar ProgressColor="{Binding Bar_Color}" 
                                     Progress="{Binding CurrentProgress}" 
                                     PropertyChanged="ProgressBar_PropertyChanged"/>
                                </StackLayout>
                            </ViewCell>
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>
            </StackLayout>

</ContentPage>

 public partial class PatientView : ContentPage
    {
        public PatientView()
        {
            InitializeComponent();

            BindingContext = App.PVM;
            Patients.ItemsSource = App.PVM.AllPatient;
        }
        private async void OnSelection(object sender, SelectedItemChangedEventArgs e)
        {
            if (e.SelectedItem == null)
            {
                return;
            }
            await DisplayAlert("Selecionado", e.SelectedItem.ToString(), "Ok");
            string a = e.SelectedItem.ToString().Substring(0, 12);

        }

        private void Renomear_Clicked(object sender, EventArgs e)
        {
            //replace name
            var item = (MenuItem)sender;
            (item.CommandParameter as Patient).Name = "new name";

        }


        private void ProgressBar_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
        //This is the way that i found.
        var item = (sender as ProgressBar) ;

        if(item.Progress==0)
        item.ProgressTo(1, 15000, Easing.Linear);

        if (item.Progress == 1)
        item.ProgressColor = Color.Green;

        }
    }

这是我发现将我的 ProgressBars 列表填充到对象中的方式。但它不喜欢实现解决方案的好方法,因为我无法控制我的 ProgressBar 的时间,并且 Easing "Linear" 它并不是真正与大量数字成线性关系。

ProgressTo 的第一个参数是 Progress,我想在我设置的第二个参数中显示它。

我想在我的模型中作为对象的参数实现。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Text;
using H2XA.ViewModel;
using Xamarin.Forms;

namespace H2XA.Model
{
    public class Patient:INotifyPropertyChanged
    {
        public Guid Id { get; set; }
        public DateTime examdate;
        public int cronometro;
        public decimal barCronometro;
        public Color Bar_Color;
        private string name;
        private string medidas;

        public Patient()
        {
            cronometro = 0;

            Device.StartTimer(TimeSpan.FromSeconds(15),  () =>
            {
                if (cronometro < 6)
                {
                    Bar_Color = Color.Blue;
                    cronometro++;
                }
                else
                {

                    if (cronometro == 60)
                    {
                        Bar_Color = Color.Red;
                    }
                }


                CurrentProgress = (cronometro / 60);


                return true;
            });

        }

        private decimal _currentProgress;
        public decimal CurrentProgress
        {
            get { return _currentProgress; }
            private set
            {
                _currentProgress = value;
                OnPropertyChanged();
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] String propertyName = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        public string Name
        {
            get { return name; }
            set
            {
                name = value;
                OnPropertyChanged();//Esse comando faz a tela ser atualizada quando algo é inserido.

            }
        }
        public string Medidas
        {
            get { return medidas; }
            set
            {
                medidas = value;
               OnPropertyChanged();//Esse comando faz a tela ser atualizada quando algo é inserido.

            }
        }

    }
}

但是当我这样做时,没有动画并且不更新图中的时间,只有当完成时间时,条件才起作用并且我的栏出现填充。我不知道我的绑定是否有效,对我来说我做了一些有意义的事情。

我正在检查代码并注意到我的 ProgressBar_PropertyChanged 每次都会被调用,这对我在应用程序中的效率也不利。谁能帮助我改进我的代码并组织我的功能以更好地组织我的 MVVM 项目。

提前致谢

吉尔赫姆·马克斯

【问题讨论】:

  • Patient 模型类中尝试将OnPropertyChanged(); 更改为OnPropertyChanged("CurrentProgress");
  • 它不起作用@JuniorJiang-MSFT。
  • 注意:如果删除“ProgressBar_PropertyChanged”并等待完成该栏的时间。当它完成时( "Progress=1" ),途中没有动画,但最终出现在一个实心条中。 “ProgressTo”可能有问题吗?我该如何解决?
  • ProgressTo没有问题。因为模型改变时,不要调用ProgressTo,所以最后只是一个填充的bar。等于progress = 1的效果。

标签: listview mvvm xamarin.forms progress-bar inotifypropertychanged


【解决方案1】:
  1. ProgressBar 不在 ListView 中时。 你应该Overriding the Binding Mode,目标属性上的默认绑定模式是OneWay。当你的模型数据发生变化时,进度条的进度已经设置在那里。它不会触发@987654325的这个方法@。

这里你应该使用绑定模式是TwoWay,它会正确显示。

示例代码如下:

Xaml:

 <ProgressBar x:Name="progressBar" 
                     Progress="{Binding CurrentProgress,Mode=TwoWay}" 
                     PropertyChanged="ProgressBar_PropertyChanged"/>

ContentPage:当模型数据改变时,它会起作用。

private void ProgressBar_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            //This is the way that i found.
            var item = (sender as ProgressBar);

            //if (item.Progress == 0)
                item.ProgressTo(1, 15000, Easing.Linear);

            //if (item.Progress == 1)
                //item.ProgressColor = Color.Green;

        }

您可以删除ProgressBar_PropertyChanged方法。当数据更改时,请执行以下操作:

   dataModel.CurrentProgress = 0.8;
   ...
   progressBar.ProgressTo(dataModel.CurrentProgress, 3000, Easing.Linear);
  1. ProgressBarListView 中与 MVVM 绑定时,不会发生Animation。这里有一个article 供参考。

解决方案:

这是一种使用Timer 来调度任务来更改进度数据的方法。

Timer timer; // create a timer
DataModel dataModel; // data model
private double ApiProgressData = 0; // Simulate data from Api

初始化计时器及其事件处理程序:

 timer = new Timer();
 timer.Interval = 100;
 timer.Elapsed += Timer_Elapsed;

  private void Timer_Elapsed(object sender, ElapsedEventArgs e)
    {   
        if (ApiProgressData > dataModel.CurrentProgress)
        {
            dataModel.CurrentProgress = dataModel.CurrentProgress + 0.01;
            if ((ApiProgressData - dataModel.CurrentProgress) < 0.00001)
            {
                Device.BeginInvokeOnMainThread(() =>
                {
                    timer.Stop();
                });

            }
        }
        else if (ApiProgressData < dataModel.CurrentProgress)
        {
            dataModel.CurrentProgress = dataModel.CurrentProgress - 0.01;
            if (( dataModel.CurrentProgress - ApiProgressData ) < 0.00001)
            {
                Device.BeginInvokeOnMainThread(() =>
                {
                    timer.Stop();
                });

            }
        }else{
            Device.BeginInvokeOnMainThread(() =>
                {
                    timer.Stop();
                });
        }
    }

Api数据改变后,使用Timer改变Model的数据:

 ApiProgressData = 0.8; //  Simulate data is 0.8 to test
 timer.Start();

或者你可以试试上面文章中提到的第三方库。

【讨论】:

  • 你不能使用 x: Name="progressbar" 因为它是一个进度条列表,你不能在其中使用相同的名称。没用。
  • 我放了“if(item.Progress==0)”,因为这个方法一直在调用。当您在没有“if”的情况下设置此方法时,线性看起来像一条对数曲线并且从未完成,因为每次调用您都会设置一个新的进度。
  • 我看到了您在“覆盖绑定模式”中发送给我的链接,但在那里我读到默认是单向而不是双向。顺便说一句,我尝试了这个代码,你发给我,但没有工作可能是因为我之前说过的事情。非常感谢您尝试帮助解决这个问题。
  • 只是给出一个示例代码供参考,详细代码由您的逻辑需要。默认绑定模式并不总是一种,它会根据不同的控件而改变。Twoway是ListView中的默认值,但是ProgressBar不是它。
  • 抱歉之前的回答。如果想在Listview中使用progressBar,不需要设置OneWayToSource的绑定模式。但是,MVVM无法获取ProgressBar,所以这个动画不能发生。如果想要动画,建议使用计时器让数据像动画一样更改。如果没有,您可以使用 ProgressBar 的第三方库。jimbobbennett.io/animating-xamarin-forms-progress-bars。我将使用计时器解决方案更新答案。
猜你喜欢
  • 1970-01-01
  • 2010-11-06
  • 1970-01-01
  • 2016-08-19
  • 2021-09-20
  • 2012-03-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-14
相关资源
最近更新 更多