Quantcast
Channel: かずきのBlog@hatena
Viewing all articles
Browse latest Browse all 1387

一定時間やりなおしが出来るようにする

$
0
0

メール削除とかしたけど、一定時間取返しがきくみたいなUIがありますよね。 あぁいうのどうやるんだろうというのを考えてみました。

UWPでやってみますが、WPFでもXamarin.Formsでも基本的に同じ感じになると思います。見た目凝るのが一番難しそう。

Modelの作成

とりあえず、ReactivePropertyとPrism.Coreを参照に追加して以下のコードを書きます。

using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive;
using System.Reactive.Linq;
using System.Threading.Tasks;

namespace App2
{
    class LazyActionSampleApp
    {
        public ObservableCollection<Guid> Guids { get; } = new ObservableCollection<Guid>();

        public Task<bool> AddGuidAsync(IObservable<Unit> cancel)
        {
            var guid = Guid.NewGuid();
            this.Guids.Add(guid);

            var tcs = new TaskCompletionSource<bool>();

            Observable.Return<Func<bool>>(() => true)
                .Delay(TimeSpan.FromMilliseconds(3000))
                .Amb(cancel.Take(1).Select<Unit, Func<bool>>(_ => () => { this.Guids.Remove(guid); returnfalse; }))
                .Subscribe(x => tcs.SetResult(x()));

            return tcs.Task;
        }
    }
}

Reactive ExtensionsのAmbを使うと先に発火したほうを後ろに流すことができます。これを使ってコミット処理(今回はtrueを返すだけ)とキャンセル処理(今回はコレクションに追加したものを削除する)といったFuncを合成してSubscribeして実行しています。一応処理が成功したのかキャンセルされたのかは戻り値で返すようにしました。

あとは、VMとVを作っておしまい。

using Prism.Mvvm;
using Reactive.Bindings;
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Threading.Tasks;

namespace App2
{
    publicclass MainPageViewModel : BindableBase
    {
        private LazyActionSampleApp Model { get; } = new LazyActionSampleApp();

        public ObservableCollection<Guid> Guids => this.Model.Guids;

        public ReactiveProperty<bool> IsBusy { get; } = new ReactiveProperty<bool>(false);

        public AsyncReactiveCommand AddCommand { get; }

        public AsyncReactiveCommand CancelAddCommand { get; }

        public MainPageViewModel()
        {
            this.AddCommand = new AsyncReactiveCommand(this.IsBusy.Select(x => !x).AsObservable());
            this.CancelAddCommand = new AsyncReactiveCommand(this.IsBusy.AsObservable());

            var cancelTrigger = new Subject<Unit>();
            this.AddCommand
                .Subscribe(async x =>
                {
                    this.IsBusy.Value = true;
                    await this.Model.AddGuidAsync(cancelTrigger);
                    this.IsBusy.Value = false;
                });

            this.CancelAddCommand.Subscribe(_ =>
            {
                cancelTrigger.OnNext(Unit.Default);
                return Task.CompletedTask;
            });
        }
    }
}
using Windows.UI.Xaml.Controls;

namespace App2
{
    publicsealedpartialclass MainPage : Page
    {
        private MainPageViewModel ViewModel { get; } = new MainPageViewModel();

        public MainPage()
        {
            this.InitializeComponent();
        }
    }
}
<Pagex:Class="App2.MainPage"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="using:App2"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"mc:Ignorable="d"><Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"><Grid.RowDefinitions><RowDefinition Height="Auto" /><RowDefinition Height="Auto" /><RowDefinition /></Grid.RowDefinitions><Button Content="Add"Command="{x:Bind ViewModel.AddCommand}"HorizontalAlignment="Stretch"/><Button Content="Cancel"Command="{x:Bind ViewModel.CancelAddCommand}"HorizontalAlignment="Stretch"Grid.Row="1" /><ListView ItemsSource="{x:Bind ViewModel.Guids}"Grid.Row="2" /></Grid></Page>

実行結果

こんな感じになります。

www.youtube.com


Viewing all articles
Browse latest Browse all 1387

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>