nuits.jp blog

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

Xamarin.Forms用の汎用Behaviorライブラリをリリースました

Xamarin.Forms用の汎用Behaviorライブラリをリリースました!

www.nuget.org

コード&詳細ドキュメント(まだ下記中ですが)はこちらにあります。

github.com

たとえば、こんな感じでイベント発生時にEventのパスを指定してEventのプロパティを引数にCommandを実行したり

<ListView ItemsSource="{Binding Fruits}">
    <ListView.Behaviors>
        <behaviorsPack:EventToCommandBehavior
            EventName="ItemTapped"
            Command="{Binding SelectedFruitCommand}"
            EventArgsPropertyPath="Item"/>
    </ListView.Behaviors>
public ICommand SelectedFruitCommand => new Command<Fruit>(fruits =>
{
    ...
});

こんな感じで、ボタンクリック時に確認ダイアログを表示してからCommandを実行したり

<Button Text="Show Display Alert">
    <Button.Behaviors>
        <behaviorsPack:DisplayAlertBehavior
            EventName="Clicked"
            Title="Alert Title"
            Message="Please select either."
            Accept="OK"
            AcceptCommand="{Binding AcceptCommand}"
            Cancel="Cancel""/>
    </Button.Behaviors>
</Button>

Behavior作成時の基底クラスもいくつか用意しています。例えば親のBindingContextを継承するInheritBindingBehaviorとか。

色々便利です。多分。

良かったら使っていただけると嬉しいです。
ご要望はぜひIssueへ!

.NET StandardプロジェクトをxUnitでテストする方法

.NET Standardのプロジェクトをテストするために、.NET Standardのテストプロジェクトを作成するとxUnitのテストが認識されずテストできません。
現状ではつぎのようにすることで対応できます。

  • Testプロジェクトを.NET Coreのコンソールアプリケーションとして作成する
  • NuGetからつぎのパッケージを追加する
    • Microsoft.NET.Test.Sdk 15.0.0
    • xunit 2.0.0
    • xunit.runner.visualstudio 2.0.0

これで.NET Standardのプロジェクトのテスト自体はできます。
しかし、その.NET StandardのプロジェクトがPCLライブラリ(Xamarin.Formsなど)を参照していたりすると、もうひと手間必要です。

.csprojをメモ帳などで開いて、PackageTargetFallbackを追記してあげてください。手で。

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

  <PropertyGroup>
    <TargetFramework>netcoreapp1.1</TargetFramework>
    <PackageTargetFallback>$(PackageTargetFallback);portable-win+net45+wp8+win81+wpa8</PackageTargetFallback>
  </PropertyGroup>

これでいけるはずです。

【Xamarin.Forms】汎用的なBehavior集ライブラリを作ってる

ふと思い立って、汎用的なBehaviorライブラリを作ってます。

とりあえず作っているのは

  • Eventを指定してEventが発生したら何かする抽象Behavior
  • Eventが発生したらCommandを実行するBehavior
  • DisplayAlertを表示してCommandを実行するBehavior
  • ActionSheetを表示してCommandを実行するBehavior

探せばありそうな気もしますし、一部Prismにも含まれていたりしますが、.NET Standardの学習もかねて作ってます。
まだ作ってる途中で全然テストとか書いてないけどw

動作感としてはこんな感じです。

f:id:nuitsjp:20170610193344g:plain

ちょっと見にくいけど選択した行が、下のSelectedItemに表示されていたりします。
まぁ、そこはBehaviorでやるほどではありませんが。
気になった方は良かったら続きをぜひ!

続きを読む

【メモ】Xamarin.FormsでPopModalしてもStackからPageが解放されない問題と、限定的な回避策

あくまでメモです。

  • 検証などが不十分なので、鵜呑みにはしないでください
  • ここでの回避策は特定の利用方法における限定的な回避策です
  • ModalStackが適切な状態になるわけではありません

さて

ModalStackからPageをPopすると、画面は前画面に戻るが、ModalStackにPageが残ったままになる

という問題が発生する事がある、という情報をある人から伺いました。

このことは、PageがModalStackからPopされた時に、PopされたPageと、結果表示されるPageにイベントを通知したいような場合に問題が発生します。
今回はこの時に該当問題の回避方法についてメモを残しておきます。

ModalStakの戻る処理において、アプリケーションからの処理と、AndroidやWin10mの物理Backボタンを押下され、画面が戻った後の処理を包括的に扱う場合、Xamarin.FormsではApplicationクラスのModalPoppedイベントを利用する事は適切な手段の一つです。
ModalPoppedでは、「PopされたPage」しか通知されないため、「Popされた結果、表示状態になったPage」を取得したいとすると、通常はModalStackの末尾のページを利用すればよいでしょう(ModalStackが空ならMainPage)。

こんなイメージです。

public App()
{
    ModalPopped += OnModalPopped;
    ...
}

private void OnModalPopped(object sender, ModalPoppedEventArgs e)
{
    var poppedPage = e.Modal;
    var currentPage = 0 < MainPage.Navigation.ModalStack.Count
        ? MainPage.Navigation.ModalStack.Last()
        : MainPage;
    ...
}

しかし、ModalStackからPageが削除されない可能性を考慮すると、このコードだとcurrentPageが正しく取れない可能性があります。
ではどうすれば良いか?ModalPoppingイベントを活用します。
ModalPoppingではPopされるPageがまだModalStack上に存在するので、その前の画面を取得しておくことでPop後のcurrentPageを確保しておくことができます。(ModalPoppedイベントでは正常時はStackからすでにPageが削除されているため、処理できません)

こんな感じでしょうか?

public App()
{
    ModalPopping += OnModalPopping;
    ModalPopped += OnModalPopped;
    ...
}

private Page _previousPage;
private void OnModalPopping(object sender, ModalPoppingEventArgs e)
{
    int currentIndex = MainPage.Navigation.ModalStack.Count - 1;
    for (; 0 <= currentIndex; currentIndex--)
    {
        var page = MainPage.Navigation.ModalStack[currentIndex];
        if (page == e.Modal)
        {
            break;
        }
    }
    _previousPage = 0 < currentIndex 
        ? MainPage.Navigation.ModalStack[currentIndex - 1] 
        : MainPage;
}

private void OnModalPopped(object sender, ModalPoppedEventArgs e)
{
    var poppedPage = e.Modal;
    var currentPage = _previousPage;
    ...
}

なお、この対処方法はPrism for Xamarin.Formsの次のあたりのコードを参考にしています。
github.com

ご参考にどうぞ。

Xamarin.FormsでAndroidやiOSで例外がさっぱりわかんねえよ!って時の一つの解決方法

なんだかVisual Studio 2017になって、例外が余計に分かりにくくなったような気がするのは気のせいでしょうか?
本当、どうでもいいことでミスしていて(MasterDetailPageのMaster側のPageにTitleを設定するのを忘れていた。。。とか)、でもそれに気が付けないってことがままある気がします。

そんな時、もしかしたらこれで一発解決することがあるかもしれません。
方法は簡単です。

UWPのローカルマシンでデバッグしてみる。

そうすると、例外が人間に読める感じで出力されることもある気がします。 てことで、困ったときはダメ元でお試しあれ。

デフォルトでUWPのビルドと配置が有効になっていない点にご注意ください。

今日はそれだけです!
ではまた~。

Xamarin.Forms Navigation Overview

久しぶりにJXUGでしゃべらせていただきました。

完全に物理バックボタンを忘れていたので、そのうちどこかで追記なり補足します。

jxug.connpass.com

発表に利用した資料はこちらに公開しています。

www.slideshare.net

ただ、スライドだけで理解いただけるものを作るスキルがないので、ここに話した内容も要約して載せておこうと思います。
良かったらご覧ください。

続きを読む