在从webservice服务检索数据之前和之后,从ViewModel设置ProgressBar可见性

我正在使用MVVM设计模式和MVVM Light工具包创建Windows Phone 8.1应用程序。

我正在尝试创建一个简单的登录页面,从用户获取用户名和密码并使用web服务进行身份验证。 在这个身份验证过程中,我想在页面顶部显示一个ProgressBar(加载点),以指示正在发生的事情。

我已经成功创建了我的ViewModel并绑定了我的视图,以允许我通过连接到我的登录按钮的命令来控制ProgressBar的可见性。 这可以工作,但是,只有在整个登录过程完成后,UI才会更新以显示ProgressBar,从而使得进度指示符毫无意义。

如何首先设置ProgressBar的可见性(并有UI更新),然后关闭执行我的登录过程?

这里是一些代码:

XAML

<ProgressBar IsIndeterminate="True" Height="1" Visibility="{Binding Login.ProgressVisibility, UpdateSourceTrigger=PropertyChanged, FallbackValue=Collapsed}" /> 

视图模型

 public class LoginViewModel : ViewModelBase { private IDialogService dialogService; private INavigationService navigationService; private string _username; private string _password; private Visibility _progressVisibility = Visibility.Collapsed; /// <summary> /// User login name / email address /// </summary> public string Username { get { return _username; } set { Set(() => Username, ref _username, value); } } /// <summary> /// User password /// </summary> public string Password { get { return _password; } set { Set(() => Password, ref _password, value); } } /// <summary> /// Is loading in progress /// </summary> public Visibility ProgressVisibility { get { return _progressVisibility; } set { Set(() => ProgressVisibility, ref _progressVisibility, value); } } /// <summary> /// Perform login action /// </summary> public RelayCommand LoginCommand { get; private set; } /// <summary> /// constructor /// </summary> /// <param name="dialogService"></param> public LoginViewModel(IDialogService dialogService, INavigationService navigationService) { this.LoginCommand = new RelayCommand(this.Login, CanLogin); this.dialogService = dialogService; this.navigationService = navigationService; } public void Login() { this.ProgressVisibility = Visibility.Visible; //check the credentials have been provided if (this._username == null || this._password == null) { //show dialogue dialogService.ShowMessage("Please enter you login credentials", "Login"); } else { //perform an authentication request with the service ValidateLoginRequest request = new ValidateLoginRequest(); request.Device = new Device(); request.UserName = this.Username; request.Password = this.Password; var response = Task.Run(() => LoginAsync(request)).GetAwaiter().GetResult(); if (response != null) { if (response.IsSuccessful) { navigationService.NavigateTo("Main"); } else { dialogService.ShowMessage(response.ErrorCode + " :" + response.ErrorMessage, "Login"); } } else { //failure dialogService.ShowMessage("ECOM000: An unknown error has occurred", "Login"); } } } async Task<ValidateLoginResponse> LoginAsync(ValidateLoginRequest request) { Model.RuntimeDataService proxy = new Model.RuntimeDataService(); ValidateLoginResponse response = (ValidateLoginResponse)await proxy.PostAsync(request, typeof(ValidateLoginResponse), "ValidateLogin"); return response; } public bool CanLogin() { return true; } } 

您正在创建一个后台Task ,然后导致UI线程等待响应。

尝试等待从LoginAsync方法返回的Task

 var response = await LoginAsync(request); 

这应该允许您的UI线程继续,其余的方法作为回调。

您可能需要将async关键字添加到Login方法。

我使用Kotlin加入我自己的CustomBindingAdapter来解决这个问题:

 @BindingAdapter("android:visibility") fun setVisibility(view: View, visible: Boolean) { view.visibility = if (visible) View.INVISIBLE else View.VISIBLE } 

在你的view.xml里面:首先添加数据变量:

 <data> <variable name="loginViewModel" type="yourpackage.viewmodel.LoginViewModel"/> </data> <ProgressBar android:id="@+id/login_progress_bar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:indeterminate="true" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:visibility="@{!loginViewModel.loginProgress}" /> 

您的活动必须具有:

 val binding = DataBindingUtil.setContentView<LoginViewBinding>(this, R.layout.login_view) val loginViewModel = LoginViewModel(this) binding.setLoginViewModel(loginViewModel) 

最后,您的ViewModel需要处理可见性:

  var loginProgress = ObservableField<Boolean>() fun doSomething(){ this.loginProgress.set(true) } 

并设置loginProgress.set(false)无论你需要停止progressBar。

我希望这可以帮助别人;)