はじめに
WinUI3 と MVVM toolkit を使い始めて1ヶ月ほど経ちました。(まだまだ慣れない)
この記事では、WinUI3とMVVM toolkitを組み合わせて デスクトップアプリ を開発する際、どのようにして 一定の周期で実行するタスク を実装したかを説明します。
ちなみに、ボタンを押すとラベルのテキストが変わるアプリのMVVM実装の説明は複数みかけました。でもこれは、View-ViewModelで完結してしまうんですね。
一定の周期で実行するタスクを実装するとなると Model層にも手を入れる必要がある のですが、このサンプルをなかなか見つけることができず、苦労しました。
同じように困っている誰かの一助になれば幸いです。
この記事の主な対象者
- MVVM、MVVM toolkitに興味がある人
- WinUI3に興味がある人
- WPF,UWPを扱っている人。(MVVM toolkitを使うと同じ手順で実装できるはず)
この記事の目標
- MVVM toolkit+WinUI3に定期実行するタスクを作ることができるようになる。
- WinUI3やらMVVMやら敬遠してたけど、やればできるんじゃね?と思い始める。
この記事に含めないこと
- WinUI3の説明
- MVVMの説明
- MVVM toolkitの説明
環境
- Microsoft Visual Studio Community 2022 (64 ビット) Version 17.2.6
プロジェクトを作成
まずはTemplate Studio for WinUI (C#)をインストールをします。
インストール完了後、「新しいプロジェクトの作成」からTemplate Studio for WinUI (C#)を選択し、次へ>>作成を選択します。
テンプレート作成のためのナビゲーション画面が表示されます。
アプリの種類やページの数を設定できるようになっていることが確認できます。
今回は何も考えず《作成》ボタンをクリックしてプロジェクト作成を完了させましょう。
起動確認
まずは動作することを確認しましょう。
デバッグ>デバッグの開始を選択します。
次のように表示されればOKです。
一定の周期で実行するタスクを作る
ファイルを作成
Template Studioが生成するプログラムに倣って、2つのファイル、IIntervalServive.csとIntervalServive.csをそれぞれ次のように作成します。
IIntervalServive.cs
using System;
namespace YourAppName.Contracts.Services;
public interface IIntervalService
{
}
IntervalServive.cs
using YourAppName.Contracts.Services;
namespace YourAppName.Services;
public class IntervalService : IIntervalService
{
// コンストラクタ
public IntervalService()
{
}
}
一定周期で実行する関数を実装
System.Timers.Timerクラスを用い、一定周期で実行する関数を実装します。
IntervalServive.csにTimerクラスのフィールドと、Run(),Stop(),Clock()メソッドを追加し、コンストラクタからRun()を実行します。
IntervalServive.cs
using System;
using System.Diagnostics;
using System.Timers;
using App11.Contracts.Services;
namespace App11.Services;
public class IntervalService : IIntervalService
{
Timer _timer;
// コンストラクタ
public IntervalService()
{
Run();
}
public void Run()
{
Debug.WriteLine("タイマ開始");
_timer = new Timer();
_timer.Elapsed += new ElapsedEventHandler(Clock);
_timer.Interval = 1000; // コンストラクタでも指定可
_timer.AutoReset = true; // デフォルト
_timer.Enabled = true; // timer.Start()と同じ
}
public void Stop()
{
_timer.Enabled = false; // timer.Stop()と同じ
_timer.Dispose();
Debug.WriteLine("タイマ停止");
}
private void Clock(object sender, ElapsedEventArgs e)
{
Debug.WriteLine(DateTime.Now.ToString("HH:mm:ss"));
}
}
アプリケーションにサービスを追加
作成したサービスをアプリケーションにシングルトンパターンで追加します。
App.xamlのコードビハインド(App.xaml.cs)を開きます。
NavigationServiceを追加している行の下に、IntervalServiceを追加します。
// Services
services.AddTransient<INavigationViewService, NavigationViewService>();
services.AddSingleton<IActivationService, ActivationService>();
services.AddSingleton<IPageService, PageService>();
services.AddSingleton<INavigationService, NavigationService>();
services.AddSingleton<IIntervalService, IntervalService>(); // この行を追加
// Core Services
services.AddSingleton<IFileService, FileService>();
サービスを実行
シングルトンパターンなので、追加しただけで動作してくれるのでは?と思ってしまいますが、そうなっていないようです。
サービスを実行してあげましょう。
具体的には、ViewModelにてサービスを参照するとコンストラクタが実行されるようです。(コンストラクタが実行されるのは初回のみ)
MainviewModel.csを開き、次のように実装します。
MainviewModel.cs
YourAppName.Contracts.Services;
using CommunityToolkit.Mvvm.ComponentModel;
namespace YourAppName.ViewModels;
public class MainViewModel : ObservableRecipient
{
private readonly IIntervalService _intervalService;
public MainViewModel(IIntervalService intervalService)
{
_intervalService = intervalService;
}
}
アプリケーションを起動
Clock()メソッドが一定の周期(1秒)ごとに実行されている様子が確認できます。
最後に
いかがだったでしょうか。
なんとか(?)MVVMを崩さずに一定周期で実行するタスクを実装できたかと思います。
ただ、MVVM Toolkitの仕組みを理解できておらず、なぜこの実装で動作するのか、まだ理解できておりません。
より適切な実装方法があるのかもしれません。
熟練者の方。ぜひアドバイスやフィードバックをお願いします。(o_ _)o
参考
- タイマにより一定時間間隔で処理を行うには?(サーバベースタイマ編) タイマの実装方法を参考にさせていただきました。