在从 webservice 服务检索数据之前和之后从 ViewModel 设置 ProgressBar 可见性
Set ProgressBar visibility from ViewModel before and after retrieving data from webservice service
我正在使用 MVVM 设计模式和 MVVM Light 工具包创建 Windows Phone 8.1 应用程序。
我正在尝试创建一个简单的登录页面,该页面从用户那里获取用户名和密码并通过网络服务进行身份验证。在此身份验证过程中,我想在页面顶部显示进度条(加载点)以指示正在发生的事情。
我已经成功创建了我的 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
方法。
我通过添加自己的 CustomBindingAdapter 使用 Kotlin 解决了这个问题:
@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}" />
你的 Activity 必须有:
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)
。
我希望这可以帮助其他人 ;)
我正在使用 MVVM 设计模式和 MVVM Light 工具包创建 Windows Phone 8.1 应用程序。
我正在尝试创建一个简单的登录页面,该页面从用户那里获取用户名和密码并通过网络服务进行身份验证。在此身份验证过程中,我想在页面顶部显示进度条(加载点)以指示正在发生的事情。
我已经成功创建了我的 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
方法。
我通过添加自己的 CustomBindingAdapter 使用 Kotlin 解决了这个问题:
@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}" />
你的 Activity 必须有:
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)
。
我希望这可以帮助其他人 ;)