我已经堆叠了ReactiveUI命令。 这一切都很好,但ui界面反应太慢了。为什么???? 此图显示了从用户单击操作到ReactiveCommand.IsExecuting = True
的时间 public class LoginWindowViewModel: ReactiveObject, ISupportsActivation
{
public ReactiveCommand<PasswordBox, Models.User> LoginCommand { get; }
public ReactiveCommand<Unit, Unit> CancelLoginCommand { get; }
bool _isErrorShown;
public bool IsErrorShown
{
get { return _isErrorShown; }
set { this.RaiseAndSetIfChanged(ref _isErrorShown, value); }
}
string _login;
public string Login { get { return _login; } set { this.RaiseAndSetIfChanged(ref _login, value); } }
ObservableAsPropertyHelper<bool> _isExecuting;
public bool IsExecuting { get { return _isExecuting.Value; } }
public ViewModelActivator Activator => new ViewModelActivator();
public LoginWindowViewModel(Services.AuthService service)
{
LoginCommand = ReactiveCommand.CreateFromObservable(
(PasswordBox passwordField) => Observable.StartAsync(ct => {
IsErrorShown = false;
return service.AuthBasicAsync(Login, passwordField.Password, ct);
}, RxApp.MainThreadScheduler).TakeUntil(CancelLoginCommand),
this.WhenAnyValue(vm => vm.Login).Select(q => !string.IsNullOrEmpty(q)));
CancelLoginCommand = ReactiveCommand.Create(() => { });
_isExecuting = LoginCommand.IsExecuting.ToProperty(this, x => x.IsExecuting, false);
LoginCommand.ThrownExceptions.Subscribe((obj) =>
{
if (obj is UnauthorizedAccessException)
{
IsErrorShown = true;
} else
{
throw obj;
}
});
}
}
按钮的绑定是<Button Content="{local:Gettext Login}" Width="75" Margin="5" x:Name="LoginButton" Command="{Binding LoginCommand}" CommandParameter="{Binding ElementName=PasswordField}" IsDefault="True" Click="CancelButton_Click" />
服务: 公共类AuthService { 受保护的字符串NtlmAuthUrl; protected string BasicAuthUrl; public AuthService(string basicAuthUrl,string ntlmAuthUrl) { BasicAuthUrl = basicAuthUrl; NtlmAuthUrl = ntlmAuthUrl; }
public static RestRequest MakeHandshakedRequest(string url)
{
var req = new RestRequest(url, Method.POST);
req.AddParameter("platform", Environment.OSVersion.ToString());
req.AddParameter("hash", DeviceIdService.GetDeviceId());
req.AddParameter("type", "Desktop");
req.AddParameter("name", Environment.MachineName);
req.AddParameter("app_version", Assembly.GetAssembly(typeof(App)).GetName().Version.ToString());
req.AddParameter("locale", Thread.CurrentThread.CurrentCulture.Name);
req.AddParameter("ntlm_auth_supported", App.Current.DataSource.UseNtlmAuth);
req.AddParameter("encoding", "utf-8");
return req;
}
protected Models.User ValidateResponse(IRestResponse<Models.User> user_response)
{
if (user_response.StatusCode == HttpStatusCode.Unauthorized)
{
throw new UnauthorizedAccessException();
}
if (user_response.ErrorException != null)
{
throw user_response.ErrorException;
}
if (!user_response.IsSuccessful)
{
throw new InvalidDataSourceException();
}
return user_response.Data;
}
protected async Task<Models.User> ExecuteAuthAsync(string url, RestClient client, CancellationToken token)
{
var req = MakeHandshakedRequest(url);
var user_response = await client.ExecuteTaskAsync<Models.User>(req, token);
return ValidateResponse(user_response);
}
public Task<Models.User> AuthBasicAsync(string login, string password, CancellationToken token)
{
var client = new RestClient(App.Current.DataSource.BaseUrl)
{
Authenticator = new HttpBasicAuthenticator(login, password),
Encoding = Encoding.UTF8,
};
return ExecuteAuthAsync(BasicAuthUrl, client, token);
}
}
}
查看:
public partial class LoginWindow : Window, IViewFor<LoginWindowViewModel>
{
public Models.User User { get; protected set; }
private DateTime dt_start;
public LoginWindow(Services.AuthService service)
{
ViewModel = new LoginWindowViewModel(service);
InitializeComponent();
DataContext = ViewModel;
ViewModel.LoginCommand.Subscribe((user) =>
{
User = user;
DialogResult = true;
Close();
});
ViewModel.CancelLoginCommand.Subscribe(_ =>
{
Close();
});
ViewModel.LoginCommand.IsExecuting.Subscribe(_ =>
{
MessageBox.Show("Time elapsed from click to command executing is: " + (DateTime.Now - dt_start));
});
}
public LoginWindowViewModel ViewModel { get; set; }
object IViewFor.ViewModel { get => ViewModel; set => ViewModel = value as LoginWindowViewModel; }
private void CancelButton_Click(object sender, RoutedEventArgs e)
{
dt_start = DateTime.Now;
}
}
}