7.10.2017

在Xamarin.Forms上的MVVM

ReactiveUI

最近在看Xamarin.Forms的MVVM framework,個人徧好ReactiveUI,於是找到了這篇介紹 –
A Simple Vocabulary App Using ReactiveUI and Xamarin Forms,它實作了一個猜字的遊戲,如下圖:
enter image description here

基本上它使用的方式和在Windows平台上沒有什麼差別,仍是focus在view和viewmodel的互動,沒有其它的東西,如頁面的routing、Navigation、IoC的使用等。

此程式主要的動作在WordPickViewModel中:

public WordPickViewModel(IWordRepository wordRepository)
{
    _wordRepository = wordRepository;
    WordOptions = new ObservableCollection<WordOption>();
    CorrectPct = "0%";

    // 設定狀態的條件,型別為IObservable<bool>
    var canRetrieve = this.WhenAnyValue(x => x.CanRetrieve).Select(x => x);
    var canSelect = this.WhenAnyValue(x => x.CanRetrieve).Select(x => !x);

    // 原文使用CreateAsyncTask,目前版本v7.4,要改用如下函式
    // 定義命令,此命令完成後會回傳一List<WordOption>>
    RetrieveWordCommand = ReactiveCommand.CreateFromTask<List<WordOption>>(async (arg) =>
    {
        var wordResults = await _wordRepository.GetWords(_rangeFloor, RangeCeiling);

        return wordResults.Select(wr =>
            new WordOption
            {
                Word = wr.Name,
                Definition = wr.Definition,
                WordId = wr.Id
            }).ToList();
    }, canRetrieve);

    // 原文使用CreateAsyncTask,目前版本v7.4,要改用如下函式
    SelectAnswerCommand = ReactiveCommand.CreateFromTask(async arg =>
    {
        await HandleItemSelectedAsync(arg);
    }, canSelect);

    // ObserveOn表示後續動作會在其指定的執行緒上被執行
    // Subscribe定義命令完成後的處理
    RetrieveWordCommand
        .ObserveOn(RxApp.MainThreadScheduler)
        .Subscribe(wordOptions =>
        {
            _timerCancellationToken = new CancellationTokenSource();
            NextRange();
            CanRetrieve = false;
            WordOptions.Clear();

            // randomly determine the word to challenge user with
            var rand = new Random();
            var challengeWord = wordOptions[rand.Next(wordOptions.Count)];
            ChallengeWord = $"\"{challengeWord.Word}\"";

            foreach (var item in wordOptions)
            {
                var isAnswer = item.WordId == challengeWord.WordId;
                item.IsAnswer = isAnswer;
                item.Image = isAnswer ? "check.png" : "x.png";
                WordOptions.Add(item);
            }

            TimerCountdown = 10;
            Device.StartTimer(new TimeSpan(0, 0, 1), () =>
            {
                if (_timerCancellationToken.IsCancellationRequested)
                {
                    return false;
                }

                if (TimerCountdown == 0)
                {
                    ProcessAnswer();
                    return false;
                }
                TimerCountdown--;
                return true;
            });
        });

    //Behaviors
    this.WhenAnyValue(x => x.Begin).InvokeCommand(RetrieveWordCommand);
}

不過程式中對xaml頁面的部份,都是用code behind中的程式碼產生,View和ViewModel的綁定也是,個人比較不建議這個方式,這讓xaml的優勢不再。

xamvvm

這個輕量級的framework填補了ReactiveUI缺少的部份,因此兩個可以一起合用

Prism

Xarmin.Forms上的Prism不像WPF環境下那麼龐大,它精簡了很多,當然也比ReactiveUI完整多了,若是需要可以互相配合使用。

這邊有一個不錯的教學影片可參考.。

MVVMLight

在學Wpf時主要都是使用這一個,在Xamarin.Forms上它也滿適合的,輕量且剛剛好的功能,作者也寫了一個跨平台的範例程式,另在channel9有影片介紹

另有以此為基礎的延伸框架:

Xarch-starter

可以把它當作基楚的樣板來擴充,wiki中也提到了另一個更進階的框架 - Exrin,也可以參考看看…

這些framework都滿足了最基本的需求,不過大部份的說明文件都不甚豐富,想要應用都需要一點時間;當然也可以不依靠這些framework,之前在學wpf時就看過一系列的教學沒有應用任何framework,不過後來程式一步步擴大,不斷的重構後就出來了另一個框架了,就學習層面來說這很不錯,但還是要看個人的取舍了XD。

Written with StackEdit.

沒有留言:

張貼留言