予測気温表示アプリ
ここからは、県庁所在地の予測気温を表示するアプリを作成します。県庁所在地を選ぶと、現在時から24時間先までの予測気温を表示します。予測気温のデータは、Open MeteoのWebAPIを利用します。また、県庁所在地の情報は「都道府県庁所在地 緯度経度データ」で公開されているものを使用しました。
県庁所在地と位置のモデルクラス
県庁所在地を選択するにはコンボボックスを使用するのですが、そのコンボボックスの選択肢となるデータはアプリの起動時にCSVファイルから読み込む形にしました。
県庁所在地のCSVファイルは公開されているものを少し加工し、次のようにしました。
1,北海道,札幌市,43.06417,141.34694 2,青森県,青森市,40.82444,140.74 ~略~ 47,沖縄県,那覇市,26.2125,127.68111
文字コードをUTF-8として保存し、プロジェクトフォルダにコピーしておきます。そして、ファイルのプロパティにある「出力ディレクトリにコピー」という項目を「新しい場合はコピーする」にしておきます。
CSVファイルの各行は、連番、都道府県名、県庁所在地、緯度、経度になっています。まずは、このデータを保持するモデルクラスを作っていきます。
1つの県庁所在地と位置を表すモデルクラス(CapitalPoint)とCapitalPointオブジェクトのコレクションを保持するクラス(CapitalList)を次のようにしました。
public class CapitalPoint
{
public string Name { get; init; } = string.Empty; // 県庁所在地
public double Lat { get; init; } // 緯度
public double Lon { get; init; } // 経度
}
public class CapitalList
{
// 県庁所在地のリスト
public List<CapitalPoint> Capitals { get; } = new();
~中略~
}
これらのクラスは、プロジェクトのModelフォルダに作成します。
CSVファイルの読み込み
CapitalListクラスでは、コンストラクトでCSVファイルを読み込むようにしました。
public class CapitalList
{
~中略~
// 県庁所在地のCSVファイルから、県庁所在地名と緯度経度を読み込む
public CapitalList(string filePath)
{
try
{
foreach (var line in File.ReadAllLines(filePath))
{
var items = line.Split(',');
var pt = new CapitalPoint()
{
Name = items[1] + items[2], // 都道府県名県庁所在地
Lat = Double.Parse(items[3]), // 緯度
Lon = Double.Parse(items[4]) // 経度
};
Capitals.Add(pt);
}
}
~中略~
}
}
C#でCSVファイルを読み込む方法はいくつかありますが、今回はFile.ReadAllLinesメソッドを用いてファイル内容をいったんすべて文字列配列に読み込み、その後に処理するようにしました。
CSVファイルには、ヘッダー行の有無や項目をダブルクォーテーションで囲むなど、仕様の幅があります。今回はごくシンプルなCSVファイルなので、読み込む処理もシンプルです。各行の文字列をSplitメソッドで分割し、CapitalPointオブジェクトを作ってListコレクションに追加しています。
ビューモデルとビュー
次に、この県庁所在地リストをコンボボックスで表示してみましょう。まずは、ビューモデル(MainWindowViewModel)に県庁所在地と県庁所在地リストを参照するプロパティを追加します(Greetingプロパティは削除します)。
public class MainWindowViewModel : ViewModelBase
{
// 県庁所在地
public CapitalPoint Capitalpoint { get; init; } = new();
// 県庁所在地のリスト
public IEnumerable<CapitalPoint> Capitals { get; }
public MainWindowViewModel(string filePath)
{
Capitals = new CapitalList(filePath).Capitals;
}
~中略~
}
MainWindowViewModelのコンストラクタを少し変更して、引数でCSVファイルのパス名を渡すようにしています。
ビューのMainWindow.axamlには、UI要素のコンボボックス<ComboBox>を追加します。
<StackPanel HorizontalAlignment="Center">
<ComboBox HorizontalAlignment="Center" Margin="0,10,0,0" Name="capitalComboBox" Items="{Binding Capitals}" SelectedItem="{Binding Capitalpoint}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
<StackPanel>は、複数のUIパーツを並べる枠のようなものです。ここではHorizontalAlignment属性にCenterを指定して、画面の水平位置の中央に表示されるようにしています。<StackPanel>内のUIパーツは、デフォルトでは縦に並びます。各UIパーツは、マージン(間隔)をMargin属性で、左、上、右、下の順にカンマ区切りで指定します。
<StackPanel>のなかに、まずは<ComboBox>を配置します。<ComboBox>のItems属性でコンボボックスの選択肢リストであるCapitalsプロパティをバインディングし、SelectedItem属性でCapitalpointプロパティをバインディングしています。コンボボックスの選択肢リストの表示は<ComboBox.ItemTemplate>で指定します。今回はテキストのみの表示なので、<TextBlock>を配置し、Nameプロパティを指定しています。このNameプロパティは、CapitalPointオブジェクトのNameプロパティのことです。
なお、Avalonia UIで利用できるUIパーツ(コントロール)には、次のようなものがあります。
現状では、Visual Studio利用時、WPFのようなドラッグ&ドロップでUIがデザインできるようにはなっていません。一応プレビューには対応しているのですが、うまく表示されない場合もあります。このあたりは発展途上でしょう。
コンボボックスの表示
今回は、MainWindowViewModelクラスのコンストラクタでCSVファイルのパス名を指定するように変更しました。そのため、MainWindowViewModelクラスを生成している箇所も変更が必要です。App.axaml.csにアプリケーションクラスの定義があり、そのなかのOnFrameworkInitializationCompletedメソッドのなかでMainWindowViewModelオブジェクトを生成し、DataContextプロパティに設定しています。ここで、パス名を指定するようにします。DataContextプロパティは、ビュー(MainWindow)に関連づけるビューモデル(MainWindowViewModel)を指定するものです。
~中略~
public partial class App : Application
{
public override void OnFrameworkInitializationCompleted()
{
~中略~
desktop.MainWindow = new MainWindow
{
// CSVファイルを指定して生成する
DataContext = new MainWindowViewModel("capitallatlon.csv"),
};
~中略~
}
}
ここまでで、アプリを起動してみましょう。画面中央にコンボボックスが表示され、県庁所在地が選択できるようになっているはずです。
最後に
今回はAvalonia UIを紹介しました。Avalonia UIはWPFに似たフレームワークですが、Windowsだけではなく.NETが動作する幅広い環境で利用できます。ただ、どちらかと言えばデスクトップ環境向けのフレームワークでしょう。
次回は今回のアプリの残り、ボタン処理やWebAPIの処理などを解説する予定です。
