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

Mvvm 在从webservice服务检索数据之前和之后,从ViewModel设置ProgressBar可见性,mvvm,windows-phone-8.1,async-await,mvvm-light,Mvvm,Windows Phone 8.1,Async Await,Mvvm Light,我正在使用MVVM设计模式和MVVM Light toolkit创建一个Windows Phone 8.1应用程序 我试图创建一个简单的登录页面,从用户那里获取用户名和密码,并使用Web服务进行身份验证。在这个验证过程中,我想在页面顶部显示一个进度条(加载点),以指示发生了什么 我已经成功地创建了ViewModel并绑定了视图,以允许我通过连接到登录按钮的命令控制ProgressBar的可见性。然而,这是可行的,UI只会在整个登录过程完成后更新以显示ProgressBar,这使得使用进度指示器毫

我正在使用MVVM设计模式和MVVM Light toolkit创建一个Windows Phone 8.1应用程序

我试图创建一个简单的登录页面,从用户那里获取用户名和密码,并使用Web服务进行身份验证。在这个验证过程中,我想在页面顶部显示一个进度条(加载点),以指示发生了什么

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

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

下面是一些代码:

xaml


视图模型

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;
    }
}
public类LoginViewModel:ViewModelBase
{
专用IDialogService对话框服务;
私人导航服务;
私有字符串\u用户名;
私有字符串\u密码;
私有可见性_progressVisibility=可见性。已折叠;
/// 
///用户登录名/电子邮件地址
/// 
公共字符串用户名
{
得到
{
返回_用户名;
}
设置
{
设置(()=>Username,ref _Username,value);
}
}
/// 
///用户密码
/// 
公共字符串密码
{
得到
{
返回密码;
}
设置
{
设置(()=>密码,参考密码,值);
}
}
/// 
///正在加载吗
/// 
公众能见度
{
得到
{
返回(u);;
}
设置
{
设置(()=>ProgressVisibility,ref _ProgressVisibility,value);
}
}
/// 
///执行登录操作
/// 
public RelayCommand LoginCommand{get;private set;}
/// 
///建造师
/// 
/// 
公共登录视图模型(IDialogService dialogService,INavigationService navigationService)
{
this.LoginCommand=newrelaycommand(this.Login,CanLogin);
this.dialogService=dialogService;
this.navigationService=导航服务;
}
公共无效登录()
{
this.ProgressVisibility=可见性.Visible;
//检查是否已提供凭据
if(this._username==null | | this._password==null)
{
//表演对话
dialogService.ShowMessage(“请输入您的登录凭据”,“登录”);
}
其他的
{
//使用服务执行身份验证请求
ValidateLoginRequest请求=新的ValidateLoginRequest();
request.Device=新设备();
request.UserName=此.UserName;
request.Password=此.Password;
var response=Task.Run(()=>LoginAsync(请求)).GetAwaiter().GetResult();
if(响应!=null)
{
if(response.issucessful)
{                        
导航服务。导航到(“主”);
}
其他的
{
dialogService.ShowMessage(response.ErrorCode+”:“+response.ErrorMessage,“Login”);
}
}
其他的
{
//失败
dialogService.ShowMessage(“ECOM000:发生未知错误”,“登录”);
}
}
}
异步任务LoginAsync(ValidateLoginRequest请求)
{
Model.RuntimeDataService proxy=new Model.RuntimeDataService();
ValidateLoginResponse=(ValidateLoginResponse)等待代理。PostAsync(请求,类型(ValidateLoginResponse),“ValidateLogin”);
返回响应;
}
公共bool CanLogin()
{
返回true;
}
}

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

尝试等待从
LoginAsync
方法返回的
任务

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)
val binding=DataBindingUtil.setContentView(这个,R.layout.login\u视图)
val loginViewModel=loginViewModel(此)
binding.setLoginViewModel(loginViewModel)
最后,ViewModel需要处理可见性:

    var loginProgress = ObservableField<Boolean>()
fun doSomething(){
        this.loginProgress.set(true)
}
var loginProgress=observefield()
有趣的事{
this.loginProgress.set(true)
}
并在需要停止进度条的任何位置设置
loginProgress.set(false)


我希望这能帮助其他人;)

这起作用了,谢谢。我不知道为什么我最终使用任务。运行
    var loginProgress = ObservableField<Boolean>()
fun doSomething(){
        this.loginProgress.set(true)
}