XamarinでMvvm Light(その2) – DialogServiceとNavigationServiceを入れた
前回の血圧管理手帳アプリに削除機能を追加した。
確認ダイアログを出したかったので、DialogServiceでダイアログを出すようにした。
WindowsのWPFアプリでは、MessengerとTriggerActionで出してたけど、DialogServiceの方がポピュラーっぽい?
データの一覧画面も追加して、スクロールしたら動的にデータを増やすようにした。
1.App.xaml.cs
ViewModelLocatorでIocに登録していた処理をやめて、App.xaml.csでまとめてやるようにした。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
public App() { //InitializeComponent(); //MainPage = new blood.MainPage(); //ViewModelLocator.Setup(); ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default); SimpleIoc.Default.Register<INavigationService, NavigationService>(); SimpleIoc.Default.Register<IDialogService, DialogService>(); SimpleIoc.Default.Register<IDBManager, DBManager>(); SimpleIoc.Default.Register<MainViewModel>(); SimpleIoc.Default.Register<BloodListViewModel>(); SimpleIoc.Default.Register<MainView>(); SimpleIoc.Default.Register<BloodListView>(); MainPage = new NavigationPage(ServiceLocator.Current.GetInstance<MainView>()); DialogService dialogService = (DialogService)ServiceLocator.Current.GetInstance<IDialogService>(); dialogService.Initialize(MainPage); NavigationService navigationService = (NavigationService)ServiceLocator.Current.GetInstance<INavigationService>(); navigationService.Configure("MainPage", typeof(MainView)); navigationService.Configure("BloodListPage", typeof(BloodListView)); navigationService.Initialize((NavigationPage)MainPage); } |
MainPageにはNavigationPageをnewして設定。
DBManagerもIF化してIocに登録。
各ViewModel登録時に、コンストラクタに指定したIFが自動的に読まれるようで便利だ。
参考サイトよりDialogServiceとNavigationServiceを入れて、各Initializeを呼ぶようにした。
1 2 |
dialogService.Initialize(MainPage); navigationService.Initialize((NavigationPage)MainPage); |
2.ViewModelLocator
staticでViewModelを返すだけにした。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
public class ViewModelLocator { /// <summary> /// Initializes a new instance of the ViewModelLocator class. /// </summary> public ViewModelLocator() { //ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default); ////if (ViewModelBase.IsInDesignModeStatic) ////{ //// // Create design time view services and models //// SimpleIoc.Default.Register<IDataService, DesignDataService>(); ////} ////else ////{ //// // Create run time view services and models //// SimpleIoc.Default.Register<IDataService, DataService>(); ////} } public static MainViewModel Main { get { return ServiceLocator.Current.GetInstance<MainViewModel>(); } } public static BloodListViewModel BloodList { get { return ServiceLocator.Current.GetInstance<BloodListViewModel>(); } } public static void Cleanup() { // TODO Clear the ViewModels } } |
XAMLでBindingContextの書き方
1 2 |
xmlns:vm="clr-namespace:blood.ViewModel" BindingContext="{x:Static vm:ViewModelLocator.Main}" |
3.DBManager
削除メソッドを追加した。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
public bool DeleteSync(BloodModel model) { bool ret = false; var wait = new AutoResetEvent(false); try { string url = string.Format("{0}/api/blood/{1}/{2}", _RESTServer, model.Date.ToString("yyyy-MM-dd"), model.Time); string json = JsonConvert.SerializeObject(new List<BloodModel>() { model }, new JsonConverter[] { new IsoDateTimeConverter() { DateTimeFormat = "yyyy-MM-dd" }, new TimeSpanConverter() }); HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url); httpWebRequest.Method = "DELETE"; httpWebRequest.Headers["Authorization"] = "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes("user@usr.usr:password")); //レスポンスを受け取る Task.Run(() => { var response = (IAsyncResult)httpWebRequest.BeginGetResponse((result) => { var request = (HttpWebRequest)result.AsyncState; var res = request.EndGetResponse(result); using (var stream = res.GetResponseStream()) using (var reader = new StreamReader(stream)) { string responseText = reader.ReadToEnd(); Debug.WriteLine(responseText); int sum = 0; int.TryParse(responseText, out sum); if (sum > 0) ret = true; wait.Set(); } }, httpWebRequest); }); wait.WaitOne(); } catch (Exception e) { Debug.WriteLine(e.Message); wait.Set(); } return ret; } |
4.ダイアログを出す
ダイアログが非同期なので、コマンドもasync, awaitを付けた。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
public RelayCommand DeleteCommand { get { if (_DeleteCommand == null) { _DeleteCommand = new RelayCommand(async () => { var model = new BloodModel() { Date = this.Date, Time = this.Time, Wakeup = this.Wakeup, Max = this.Max, Min = this.Min, Pulse = this.Pulse, Weight = this.Weight, Check = this.Check, Memo = this.Memo }; // Message with custom buttons and callback action. var time = string.Format("{0:00}:{1:00}", model.Time.Hours, model.Time.Minutes); await _DialogService.ShowMessage(string.Format("{0} {1}\n削除しますか?", model.Date.ToString("yyyy-MM-dd"), time), "削除確認", buttonConfirmText: "はい", buttonCancelText: "いいえ", afterHideCallback: (confirmed) => { if (confirmed) { // User has pressed the "confirm" button. if (_DBManager.DeleteSync(model)) { var list = _DBManager.ReadSync(DateTime.Now.AddDays(-10), DateTime.Now); BloodList = new ObservableCollection<BloodModel>(list.OrderByDescending(x => x.Time).OrderByDescending(x => x.Date)); Result = _DeleteSuccess; Clear(); SelectedItem = null; } else { Result = _DeleteError; } } else { // User has pressed the "cancel" button // (or has discared the dialog box). // ... } }); } ,() => { return true; }); } return _DeleteCommand; } } |
ダイアログでた。(∩´∀`)∩
5.画面遷移
遷移先のページキーを指定する。
1 |
_NavigationService.NavigateTo("BloodListPage"); |
遷移先にはヘッダに戻るリンクが表示される。
ListViewがショボいな(´・ω・`)。。。GridViewみたくしたいな。
6.ListViewの動的データ追加
①XAML
ListViewの最下行が表示されたら、ItemAppearingイベントが走るのので、EventToCommandする
1 2 3 4 |
<ListView Grid.Row="11" Grid.ColumnSpan="2" ItemsSource="{Binding BloodList}" RowHeight="20" SelectedItem="{Binding SelectedItem}"> <ListView.Behaviors> <bhv:EventToCommandBehavior EventName="ItemAppearing" Command="{Binding ItemAppearingCommand}"/> </ListView.Behaviors> |
②VM
ItemAppearingCommandで追加検索して、ListViewのItemsSourceのObservableCollectionに追加する
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
private RelayCommand<ItemVisibilityEventArgs> _ItemAppearingCommand; /// <summary> /// ContentRenderedCommand /// </summary> public RelayCommand<ItemVisibilityEventArgs> ItemAppearingCommand { get { if (_ItemAppearingCommand == null) { _ItemAppearingCommand = new RelayCommand<ItemVisibilityEventArgs>((e) => { var item = e.Item as BloodModel; if (item != null && item.Date > DateStart && item == BloodList.Last()) { var list = _DBManager.ReadSync((item.Date.Date.AddDays(-1) - DateStart.Date) > TimeSpan.FromDays(10) ? item.Date.AddDays(-11) : DateStart, item.Date.AddDays(-1)); if (list != null) { foreach (var s in list.OrderByDescending(x => x.Time).OrderByDescending(x => x.Date)) { BloodList.Add(s); } } } }); } return _ItemAppearingCommand; } } |
—
参考サイト
https://marcominerva.wordpress.com/2014/10/14/dialogservice-in-mvvm-light-v5/
https://marcominerva.wordpress.com/2014/10/10/navigationservice-in-mvvm-light-v5/