#c# #wpf #async-await #reactiveui
#c# #wpf #асинхронный-ожидание #reactiveui
Вопрос:
Все, что я хочу, это получить некоторые данные из сервиса, а затем показать их с помощью DataGrid в новом окне после нажатия кнопки. Прежде всего, я должен упомянуть, что загрузка данных должна размещаться в новом окне, а не в его владельце.
Проблема в том, что любой подход, связанный с трудоемкой задачей с помощью ReactiveCommands (либо CreateFromTask, либо CreateFromObservable), не приносит мне никакого результата. Я успешно получаю свои данные из службы, затем свойство Data также успешно обновляется, НО я не вижу ничего, кроме имен столбцов DataGrid. Если я заменю LoadDataCommand на just Data = new List<...>() { new ..., new...}
(hardcoded), все работает нормально, поэтому проблема заключается в загрузке данных и передаче этих данных в пользовательский интерфейс, а не в привязке, как я привык думать.
К сожалению, я совсем новичок в ReactiveUI, и я прочитал несколько статей в reactiveui.net/docs и ответы других здесь, прежде чем спрашивать, но ни один из них мне не помогает, хотя кажется, что я применяю те же подходы.
Владелец:
var window = new PaymentsDetailingView(request)
{
WindowStartupLocation = WindowStartupLocation.CenterScreen
};
window.ShowDialog();
Затем я начинаю загружать данные в конструктор следующим образом:
xaml.cs
public PaymentsDetailingView(CounterpartyPaymentRequest request)
{
ViewModel = new PaymentsDetailingViewModel(request);
InitializeComponent();
this.WhenActivated(disposables =>
{ // some bindings (to DataGrid too)
this.WhenAnyValue(x => x.ViewModel.LoadDataCommand).SelectMany(x => x.Execute()).Subscribe()
.DisposeWith(disposables);
});
ViewModel:
public List<PaymentsDetailingData> Data
{
get => _data;
set => this.RaiseAndSetIfChanged(ref _data, value);
}
public ReactiveCommand<Unit, List<PaymentDetailingResponseModel>> LoadDataCommand { get; set; }
public PaymentsDetailingViewModel(CounterpartyPaymentRequest request)
{
Request = request;
//LoadDataCommand = ReactiveCommand.CreateFromTask(GetAndShowPaymentDetailedDataAsync);
LoadDataCommand =
ReactiveCommand.CreateFromObservable(() => Observable.StartAsync(GetAndShowPaymentDetailedDataAsync, RxApp.MainThreadScheduler));
//LoadDataCommand = ReactiveCommand.CreateFromObservable(
// () =>
// Observable.FromAsync(GetAndShowPaymentDetailedDataAsync));
LoadDataCommand/*.ObserveOn(RxApp.TaskpoolScheduler)*/
.Subscribe(x => Data = x.AddTotalRow().ToUiModels());
LoadDataCommand.ThrownExceptions.Subscribe(e => this.Log().Error(e));
LoadDataCommand.IsExecuting.ToProperty(this, x => x.IsLoading, out _isLoading);
}
private async Task<List<PaymentDetailingResponseModel>> GetAndShowPaymentDetailedDataAsync()
{
var arService = Locator.Current.GetService<IAnalyticalReportingService>();
var results = await arService.ExecuteDetailedCounterpartyPaymentInfo(Request, new CancellationToken());
return results;
}
}
Комментарии:
1. Вероятно, сначала стоит проверить, что привязки на стороне представления
OneWay
, например{Binding Value, Mode=OneWay}
. Такие платформы, как UWP и некоторые элементы управления WPF, как правило, используютOneTime
привязки по умолчанию. Однако это не применимо к типобезопасным привязкам ReactiveUI. Также стоит добавить.ObserveOn(RxApp.MainThreadScheduler)
(неTaskPoolScheduler
) прямо перед вызовом.Subscribe
наLoadDataCommand
..ObserveOn(RxApp.MainThreadScheduler)
гарантирует, что внутренний кодSubscribe
выполняется в основном потоке.2. Если ничего из этого не помогает, вероятно, стоит сделать минимальную проверку и перейти к ReactiveUI Slack (
reactiveui
канал поддержки).