Xamarin.Macで作ったデスクトップアプリで、プロジェクト内に用意した設定やテンプレートなどのファイルを実行時に読み込ませたい。
Xamarin.Macでlog4netを使うため、起動時にXMLで書かれたファイルを読みこんでlog4netに渡したい。
また、アプリに簡易的なWebサーバを持たせたい時にテンプレートをファイルを読み込みたいという場面があり、その際にも同様の方法で実現した。
今回はファイルを読み込む例としてプロジェクト内のJSONファイルを読み込み、前回作成した表に表示することにする。
前回の記事:DelegateとDataSourceを使ったTableViewにインクリメンタルサーチを実装する
読み込むJSONファイルを作成する。
プロジェクト下にResourcesというフォルダがあるのでここにファイルを追加する。ファイル名はmembers.jsonとした。
members.json
{"members":[{"Name":"a2see","TwitterId":"a2see"},{"Name":"うぇるち","TwitterId":"welchi_"},{"Name":"想間ミレイ","TwitterId":"zerovabi"},{"Name":"月見ねぎとろ","TwitterId":"tukimi_negitoro"},{"Name":"創好リナ","TwitterId":"TsukusuLina"},{"Name":"でんじぃ","TwitterId":"den_oldman"},{"Name":"とりえ","TwitterId":"trpla226"},{"Name":"なもなき","TwitterId":"nam0naki"}]}
ソリューションウィンドウからmembers.jsonファイルのコンテキストメニューを表示し、「プロパティ」をクリックする。
ビルド > ビルドアクションドロップダウンで「EmbeddedResource」を選択する。
EmbeddedResourceを選ぶと、「リソースID」にデフォルトのものが設定される。これをクリップボードにコピーしておく。
今回は「tablesearch.Resources.members.json」というIDになった。
今回はViewControllerの生成時にファイルを読みこむようにする。
Assembly#GetManifestResourceStream()にリソースIDを渡すことで、Streamとして取得することができる。
あとはStreamを文字列として読み込み、欲しい形に変換して前回作った表示処理に食わせる。
なお、JSONのパースのにあたってNugetでNewtonsoft.Jsonを導入した。
ViewController.cs(該当部分)
// Resource内のファイルを取得var assm= Assembly.GetExecutingAssembly();var membersStream= assm.GetManifestResourceStream("tablesearch.Resources.members.json");// string型としてファイルの最後まで読み込むvar membersJson=newStreamReader(membersStream).ReadToEnd();// 取得したJSONをList<Member>に変換var membersJObj= JObject.Parse(membersJson);var membersJArray=(JArray)membersJObj["members"];Members= membersJArray.Select(jt=> jt.ToObject<Member>()).ToList().AsReadOnly();
JSONファイルの内容をテーブルに表示することができた。
Mac OS X 10.15.6
Visual Studio for Mac Community 8.8.1(build 37)
Xamarin Mac 7.0.0.15
XCode Version 12.2
前回のコードに変更を加えて作成した今回のViewController.csファイルの全容を公開しておく。
ViewController.cs
usingSystem;usingSystem.Collections.Generic;usingSystem.IO;usingSystem.Linq;usingSystem.Reflection;usingAppKit;usingFoundation;usingNewtonsoft.Json.Linq;namespacetablesearch{publicpartialclassViewController:NSViewController{readonlyMemberTableViewDataSource dataSource=newMemberTableViewDataSource();IReadOnlyCollection<Member> Members;publicViewController(IntPtr handle):base(handle){// Resource内のファイルを取得var assm= Assembly.GetExecutingAssembly();var membersStream= assm.GetManifestResourceStream("tablesearch.Resources.members.json");// string型としてファイルの最後まで読み込むvar membersJson=newStreamReader(membersStream).ReadToEnd();// 取得したJSONをList<Member>に変換var membersJObj= JObject.Parse(membersJson);var membersJArray=(JArray)membersJObj["members"]; Members= membersJArray.ToList().Select(jt=> jt.ToObject<Member>()).ToList().AsReadOnly(); dataSource.Members=newList<Member>(Members);}publicoverridevoidViewDidLoad(){base.ViewDidLoad(); MemberTableView.DataSource= dataSource; MemberTableView.Delegate=newMemberTableViewDelegate(dataSource);}publicoverrideNSObject RepresentedObject{get{returnbase.RepresentedObject;}set{base.RepresentedObject=value;// Update the view, if already loaded.}}partialvoidKeywordChanged(NSObject sender){var keyword=((NSSearchField)sender).StringValue; dataSource.Members= Members.Where(member=> member.Name.Contains(keyword)).ToList(); MemberTableView.ReloadData();}}publicclassMemberTableViewDataSource:NSTableViewDataSource{publicList<Member> Members{get;set;}=newList<Member>();publicoverridenintGetRowCount(NSTableView tableView){return Members.Count;}}publicclassMemberTableViewDelegate:NSTableViewDelegate{privateconststring CellIdentifier="MemberCell";privateMemberTableViewDataSource dataSource;publicMemberTableViewDelegate(MemberTableViewDataSource dataSource){this.dataSource= dataSource;}publicoverrideNSViewGetViewForItem(NSTableView tableView,NSTableColumn tableColumn,nint row){NSTextField view=(NSTextField)tableView.MakeView(CellIdentifier,this);if(view==null){ view=newNSTextField(); view.Identifier= CellIdentifier; view.BackgroundColor= NSColor.Clear; view.Bordered=false; view.Editable=false; view.Selectable=false;}var member= dataSource.Members[(int)row];switch(tableColumn.Title){case"Name": view.StringValue= member.Name;break;case"Twitter ID": view.StringValue= member.TwitterId;break;}return view;}}}
また、Newtonsoft.Jsonでデシリアライズするに当たってMemberクラスの定義も変更したので、変更後のコードを以下に掲載する。
Member.cs
namespacetablesearch{publicclassMember{publicstring Name;publicstring TwitterId;publicMember(string name,string twitterId){ Name= name; TwitterId= twitterId;}}}
バッジを受け取った著者にはZennから現金やAmazonギフトカードが還元されます。