nuits.jp blog

C#, Xamarin, WPFを中心に書いています。Microsoft MVP for Development Technologies。

Xamarin(Formsもね)で.NET Standard 2.0なライブラリを利用する

Visual Studio 2017 Update 3がリリースされたことで、待望の.NET Standard 2.0が利用できるようになりました。
XamarinでもAndroidやiOSからは既に利用可能なようです。UWPは少々お待ちください?(少々っていつ?誰か教えて

さて、使うにはまずは.NET Standard 2.0を利用できる環境にする必要があります。
こちらの記事を参照してください。

www.nuits.jp

www.nuits.jp

手順としては簡単です。SS取り損ねたので文字だけでごめんなさい。
今回はXamarin.Formsを例にしていますが、Xamarin.Nativeから.NET Standardの共通ライブラリを利用する場合も大差ないはずです。

.NET Standard対応のPreview版のXamarin.Formsを使う

  1. PCLプロジェクトを削除する(AppとMainは取っとくと楽です)
  2. .NET Standard 2.0のクラスライブラリを作成する
  3. .NET Standard 2.0の.csprojを開いて編集する(以下を参照)
  4. AppとMainクラスを追加する
  5. AndroidとiOSのプロジェクトのXamarin.Formsのパッケージを2.3.5.256-pre6に上げる
  6. AndroidとiOSのプロジェクトから、.NET Standardライブラリのプロジェクトへ参照を追加する
  7. Androidの各種ライブラリをNuGetから最新版をダウンロードし、リビルドする
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <Compile Update="**\*.xaml.cs" DependentUpon="%(Filename)" />
    <EmbeddedResource Include="**\*.xaml" SubType="Designer" Generator="MSBuild:UpdateDesignTimeXaml" />
  </ItemGroup>
  
  <ItemGroup>
    <PackageReference Include="Xamarin.Forms" Version="2.3.5.256-pre6" />
  </ItemGroup>
</Project>

これだけです。
簡単ですね。

いつからか不明ですが、こちらの問題は解消されていて、<None Remove=“***.xaml” />は不要になっている気がします?
https://bugzilla.xamarin.com/show_bug.cgi?id=55591

PCL版のStableなXamarin.Formsを使う

そんなに難しい事ないです。
.NET Standardのライブラリでは、PCLのライブラリを明示的にどのプロファイルのものを利用するのか指定する「PackageTargetFallback」という機能があるのでそれを利用します。
上の手続きの内、.csprojを次のように記述してください。

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <PackageTargetFallback>portable-net45+win8+wpa81+wp8</PackageTargetFallback>
  </PropertyGroup>

  <ItemGroup>
    <Compile Update="**\*.xaml.cs" DependentUpon="%(Filename)" />
    <EmbeddedResource Include="**\*.xaml" SubType="Designer" Generator="MSBuild:UpdateDesignTimeXaml" />
  </ItemGroup>
  
  <ItemGroup>
    <PackageReference Include="Xamarin.Forms" Version="2.3.4.247" />
  </ItemGroup>
</Project>

まだ未検証なとこ

.NET StandardプロジェクトでNuGetパッケージを参照していると、プラットフォーム側でエラーがでるかもしれません(1.6では出ていた)。
その場合はこちらのブログを参照して、CopyNuGetImplementationsなどの設定をプラットフォーム側に追加してあげてください。

medium.com

以上です!ワクワクしますね! ライブラリ作成者としては.NET Standardに統一されていくのに幸せを感じざるをえません。

.NET Standard 2.0対応クラスライブラリを作る

Visual Studio 2017 Update 3の個人的な目玉は何と言っても、.NET Standard 2.0対応です。
という訳で、早速Xamarinの共通部分を2.0にして試してみましょう!

f:id:nuitsjp:20170815105803p:plain

入ってないのかよ(´・ω・`)
しかも、「他のフレームワークをインストールする」のリンク先に無いし(´・ω・`)

てことで、.NET Core SDK入れたら解決するんじゃね?ってことでここから入れてみました。

www.microsoft.com

そして解決しました。

f:id:nuitsjp:20170815110119p:plain

ちゃんちゃん!ってか、入れといてよ最初からさ(´・ω・`)

Visual Studio 2017 Update 3でAzure Functions and WebJobs Toolsを有効にする方法

Visual Studio 2017 Update 3では、デフォルトでAzure Functions and WebJobs Toolsがインストールされているのですが、おそらく?PreviewのUpdate3用の様で、デフォルトではAzure Functionsのプロジェクトテンプレートが有効になりません。

f:id:nuitsjp:20170815100754p:plain

個別にUpdate 3を入れると、Azure Functions and WebJobs Toolsインストールされて、更新できる状態となっていますのでそれを更新かける必要があるようです。

f:id:nuitsjp:20170815100848p:plain

Update掛けたら無事、Azure Functionsのプロジェクトテンプレートが表示されました。

f:id:nuitsjp:20170815100917p:plain

それだけ!

Visual Studio 2017 Update 2へUpdate3を適用する方法

普段Visual Studioの更新は、VSメニューバーの「ツール」>「拡張機能と更新プログラム」から入れられた気がするのですが、どうも今回は2017.08.15時点ではそこから上げられないようです?

f:id:nuitsjp:20170815094207p:plain

という訳で、Visual Studio Installerを手動で起動して(インストーラーはダウンロードしてもいいし、次のように検索しても出てくるはずです)更新すれば適用できるようです。

f:id:nuitsjp:20170815094350p:plain

インストーラーを起動したら、あとは更新ボタンを押すだけで現時点ではそんなに待たずにアップデートできました。

f:id:nuitsjp:20170815094427p:plain

それだけです。チャンチャン!

KAMISHIBAIセルフ プロモーション:一貫性を保ったイベント通知

f:id:nuitsjp:20170813232926p:plain

先日これまでのXamarin.Formsの経験や、PrismのPageNavigationServiceへの貢献を通して得たノウハウを整理して形にした、KAMISHIBAI for Xamarin.Formsをリリースしました。 前述のエントリーや、Github上のドキュメントでもKAMISHIBAIのメリットについては述べているのですが、少しずつ掘り下げて解説したいと思います。 まずは

  • 一貫性を保ったイベント通知

について説明したいと思います。これはXamarin.Formsを素でつかっていると非常に面倒な領域です。つぎの図を見てください。

f:id:nuitsjp:20170813233720p:plain

KAMISHIBAIではPageの状態遷移に伴ってつぎのようなイベントが発行されます。

イベント 想定する実装内容 パラメーター
OnInitialize リソースの初期化処理など
OnLoaded OnUnloadedで非活性化されるリソースの活性化 ×
OnUnloaded リソースの非活性化 ×
OnClosed リソースの解放 ×

これらのイベント通知があらゆるPageの状態遷移で保たれていることが、KAMISHIBAIの強みの一つです。
どういう事かというと、通常だと実現困難な次のようなケースでも、一貫して振る舞うということです。

  1. NavigationPageのNavigationBarやスワイプ、物理バックボタンによる戻る処理
  2. TabbedPageの選択Tabの変更
  3. CarouselPageの表示Pageの変更
  4. ModalStackの物理バックボタンによる戻る処理

これらを見ると、画面遷移イベントだけではない(INavigationが絡まないものはNavigationじゃないという意見もあるので)ため、画面遷移イベントというよりは、Page状態変更イベントといった方が良いでしょう。

1.~3.については、PageをPushする際にBehaviorを外部からインジェクションするという、私が勝手に「Injection Behavior of outside」と呼んでいるパターンを利用して実現しています。このあたりのコードです。

NavigationPage、TabbedPage、CarouselPageにはそれぞれ専用のBehaviorをインジェクションしています。例えばNavigationPageではPoppedイベントをハンドルして適切に処理するNavigationPageBehaviorをインジェクションしています。

また4.については、ApplicationのPopModalイベントをここらへんでハンドルして処理しています。

これらはほぼXamarin.Forms.INavigationを薄くラップするNavigatorクラスを中心に実現していますので、MVVM系の機能を利用せずとも、Navigatorクラス(とApplicationService)だけ利用するという選択肢もありです。これら(と周辺クラス群)が

  • 一貫性を保ったイベント通知
  • 複合Pageへの再帰的なイベント通知
  • 型安全な遷移パラメーター

を実現しているので、KAMISHIBAIの実装技術的な方面ではほぼ全てと言って良いでしょう。

このあたりの強い一貫性を保ったイベント通知は、アプリケーション構築の強い味方になると信じています。

Xamarin.Forms.GoogleMaps.Bindings 2.1.0の追加機能解説

昨日、Xamarin.Forms.GoogleMaps.Bindings 2.1.0のリリースを告知しましたが、あれだけだと不親切なので使い方が少し癖のある部分の解説を追記しておきます。

www.nuits.jp

追加した機能のうち、つぎの3つは少し使い方が特殊です。

  • Support MoveCamera
  • Support AnimateCamera
  • Support TakeSnapshot

とはいえ、どれか一つ覚えてしまえば基本的に他の機能も同じ方式に則っているので理解は容易でしょう。

というわけで、MoveCameraを例にとって説明します。

Mapの表示を位置や(三次元的な)角度を指定して、即座に変更するための機能がXamarin.Forms.GoogleMapsにはあります。
それをViewModelから利用するための機能を追加しました。

具体的にはViewModelに次のようなコードを追記します。

public MoveCameraRequest MoveCameraRequest { get; } = new MoveCameraRequest();

public Command MoveToTokyoCommand => new Command(() =>
{
    MoveCameraRequest.MoveCamera(CameraUpdateFactory.NewCameraPosition(
        new CameraPosition(
            new Position(35.681298, 139.766247), // Tokyo
            17d, // zoom
            45d, // bearing(rotation)
            60d // tilt
        ))); ;
});

MoveCameraRequestというプロパティを公開し、そのプロパティのMoveCameraメソッドを呼び出して利用します。
ちゃんと本家と同じく、Task<AnimationStatus>を返してくれます。
TakeSnapshotもちゃんとTask<Stream>を返してくれるため、投げっぱなしではなくちゃんとViewModel側で結果を受け取って処理できるようにしてあります。

もちろんこれだけではだめで、View側にBehaviorを追加して、このMoveCameraRequestからの要求を受け付けてMapへ伝達してあげる必要があります。

<googleMaps:Map>
    <googleMaps:Map.Behaviors>
        <bindings:MoveCameraBehavior Request="{Binding MoveCameraRequest}"/>
    </googleMaps:Map.Behaviors>
</googleMaps:Map>

こんな感じです。
簡単ですね。

つぎの機能にも簡単に触れておきましょうか。

  • Support InfoWindowClicked
  • Support InfoWindowLongClicked
  • Support MyLocationButtonClicked

これらにはMapのイベントを監視し、イベント発生時にイベントパラメーターを渡してCommandを発行するBehaviorとして追加しました。
今までも類似のものはありましたので説明は不要かもしれませんが。

具体的にはViewで次のように記述します。

<googleMaps:Map>
    <googleMaps:Map.Behaviors>
        <bindings:InfoWindowClickedToCommandBehavior Command="{Binding InfoWindowClickedCommand}"/>
        <bindings:InfoWindowLongClickedToCommandBehavior Command="{Binding InfoWindowLongClickedCommand}"/>
        <bindings:MyLocationButtonClickedToCommandBehavior Command="{Binding MyLocationButtonClicked}"/>
    </googleMaps:Map.Behaviors>
</googleMaps:Map>

特化型のEventToCommandBehaviorです。

てことで、簡単ですが今回はこれだけ。
それではまた!

Release Xamarin.Forms.GoogleMaps.Bindings 2.1.0

ちょっと放置状態になってしまっていたXamarin.Forms.GoogleMaps.Bindingsを、「だいたい」Xamarin.Forms.GoogleMaps 2.1.0まで対応しました。
未対応機能があれば、良かったら教えてください。

とりあえず、対応内容は以下の通りです。

  • Transition to .NET Standard 1.0
  • Support Xamarin.Forms.GoogleMaps 2.1.0
  • Support MoveCamera
  • Support AnimateCamera
  • Support TakeSnapshot
  • Support InfoWindowClicked
  • Support InfoWindowLongClicked
  • Support MyLocationButtonClicked

preview.nuget.org