前提・実現したいこと
Xamarin.FormsをPrism(MVVM)+ReactivePropertyで書いています。
Age、Name、Genderを入力または選択後、PushTappedでListViewに追加するような機能を作成しているのですが以下二つの問題点が発生しましたのでご助言を求めます。
1.ReactiveProperty<独自クラス>の場合のVとVMのBindingがうまくいきません。
2.ObservableCollectionのVMとMの双方向同期の記述方法がわかりません。
試したこと
1.に関しては独自クラスを使わずintやstringで分離した場合は正しく動作しました。以下コードでは正しく動いておらず、VMのInputPersonが常に空白になってしまいますのでPushTappedでは空白のListViewが追加されます。
2.に関しては以下にあるようにToReadOnlyReactiveCollectionを使ってVM←Mでは再現できましたが、その場合Model側にもInputPersonプロパティが必要になっていて、これが無駄な気がしています。VMのListViewに追加するだけでM側も同期して欲しいのです。
該当のソースコード
[View]
xaml
1<?xml version="1.0" encoding="utf-8" ?> 2<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" 3 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 4 x:Class="JsonSample.Views.MainPage" 5 Title="JsonTest"> 6 7 <Grid> 8 <Grid.ColumnDefinitions> 9 <ColumnDefinition Width="*" /> 10 <ColumnDefinition Width="2*" /> 11 </Grid.ColumnDefinitions> 12 <StackLayout Grid.Column="0"> 13 <Picker Title="年齢" ItemsSource="{Binding AgeList}" SelectedItem="{Binding InputPerson.Age.Value}"/> 14 <Entry Placeholder="名前" Text ="{Binding InputPerson.Name.Value}" Keyboard="Text"/> 15 <Picker Title="性別" ItemsSource="{Binding GenderList}" SelectedItem="{Binding InputPerson.Gender.Value}" /> 16 <Button Text="追加" Command="{Binding PushTapped}"/> 17 </StackLayout> 18 <ListView Grid.Column="1" ItemsSource="{Binding ListView}"> 19 <ListView.ItemTemplate> 20 <DataTemplate> 21 <ViewCell> 22 <Grid> 23 <Grid.ColumnDefinitions> 24 <ColumnDefinition Width="*" /> 25 <ColumnDefinition Width="3*" /> 26 <ColumnDefinition Width="*" /> 27 </Grid.ColumnDefinitions> 28 <Label Grid.Column="0" Text="{Binding Age}" /> 29 <Label Grid.Column="1" Text="{Binding Name}" /> 30 <Label Grid.Column="2" Text="{Binding Gender}" /> 31 </Grid> 32 </ViewCell> 33 </DataTemplate> 34 </ListView.ItemTemplate> 35 </ListView> 36 </Grid> 37 38</ContentPage>
[ViewModel]
C#
1using JsonSample.Models; 2using Prism.Navigation; 3using Reactive.Bindings; 4using Reactive.Bindings.Extensions; 5using System; 6using System.Linq; 7using System.Reactive.Disposables; 8using System.Collections.ObjectModel; 9 10namespace JsonSample.ViewModels 11{ 12 public class MainPageViewModel : ViewModelBase, IDisposable 13 { 14 private CompositeDisposable Disposable { get; } = new CompositeDisposable(); 15 16 public ReadOnlyReactiveCollection<Person> ListView { get; private set; } 17 public ObservableCollection<int> AgeList { get; private set; } = new ObservableCollection<int>(); 18 public ObservableCollection<string> GenderList { get; private set; } = new ObservableCollection<string>(); 19 20 public ReactiveProperty<Person> InputPerson { get; private set; } = new ReactiveProperty<Person>(); 21 22 public ReactiveCommand PushTapped { get; private set; } = new ReactiveCommand(); 23 24 private Commander commander = new Commander(); 25 26 public MainPageViewModel(INavigationService navigationService) 27 : base(navigationService) 28 { 29 //Pickerリスト作成 30 AgeList = new ObservableCollection<int>(Enumerable.Range(1, 100).ToList()); 31 GenderList = new ObservableCollection<string>() { "男", "女", "不明" }; 32 33 //ViewModel←Model 34 ListView = commander.Commanders.ToReadOnlyReactiveCollection().AddTo(this.Disposable); //本当は双方向にしたかった 35 36 //ViewModel→Model 37 InputPerson = ReactiveProperty.FromObject(commander, x => x.InputPerson).AddTo(this.Disposable); 38 39 //Button 40 PushTapped.Subscribe(_ => commander.Push()); 41 //PushTapped.Subscribe(_ => ListView.Add(InputPerson)); 双方向だったならこんな感じで行けた? 42 43 } 44 45 public void Dispose() 46 { 47 this.Disposable.Dispose(); 48 } 49 } 50} 51
[Model]
C#
1using Prism.Mvvm; 2using System.Collections.ObjectModel; 3 4namespace JsonSample.Models 5{ 6 public class Person : BindableBase 7 { 8 private int age; 9 public int Age 10 { 11 get => age; 12 set => SetProperty(ref age, value); 13 } 14 15 private string name; 16 public string Name 17 { 18 get => name; 19 set => SetProperty(ref name, value); 20 } 21 22 private string gender; 23 public string Gender 24 { 25 get => gender; 26 set => SetProperty(ref gender, value); 27 } 28 } 29 30 public class Commander : BindableBase 31 { 32 private Person inputPerson; 33 public Person InputPerson 34 { 35 get => inputPerson; 36 set => SetProperty(ref inputPerson, value); 37 } 38 39 public ObservableCollection<Person> Commanders { get; private set; } = new ObservableCollection<Person>(); 40 41 public void Push() 42 { 43 Commanders.Add(InputPerson); 44 } 45 46 } 47 48}
その他
初心者である為、上記質問以外で直したほうが良いところがもしあればご指摘いただけると助かります。
回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/11/08 23:49 編集
2018/11/09 01:19
2018/11/09 06:38