Microsoft 系のあれこれ

港区の SIer で よくわからんことをしている人です。Xamarin 中心でした。(過去形)

Xamarin.Formsでぺこぺこ凹むアイコンボタンを作った

Image だけをボタンにしたいケースが多々あり、TapGestureRecognizer で簡単に作れるのですが、押した感がなくイマイチだし好みに合うヤツが見当たらなかったので作りました。
f:id:ShunsukeKawai:20170106115747g:plain
わかりにくいですが、黒い背景でも微妙にボタン裏の色が変わっています。

凹む処理はここを参考にしました。
app-evolve/FavoriteImage.cs at master · xamarinhq/app-evolve · GitHub

最初は Image コントロールだけを拡張していましたが、それだと凹ますと背景色まで凹んでしまいかっこ悪かったので Content View の中に Image を入れました。

IconButton.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentView
    x:Class="IconButtonSample.Controls.IconButton"
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
    <Image x:Name="imgIcon" BindingContextChanged="imgIcon_BindingContextChanged" />
</ContentView>
IconButton.xaml.cs
using System;
using System.Threading.Tasks;

using Xamarin.Forms;

namespace IconButtonSample.Controls
{
    public partial class IconButton : ContentView
    {
        private bool addedAnimation;

        public static readonly BindableProperty IconSourceProperty =
            BindableProperty.Create(
                "IconSource",
                typeof(ImageSource),
                typeof(IconButton),
                null,
                propertyChanged: (bindable, oldValue, newValue) =>
                {
                    ((IconButton)bindable).IconSource = (ImageSource)newValue;
                }
            );

        public ImageSource IconSource
        {
            get { return (ImageSource)GetValue(IconSourceProperty); }
            set
            {
                SetValue(IconSourceProperty, value);
                imgIcon.Source = value;
            }
        }

        public static readonly BindableProperty IconMarginProperty =
            BindableProperty.Create(
                "IconMargin",
                typeof(Thickness),
                typeof(IconButton),
                new Thickness(0),
                propertyChanged: (bindable, oldValue, newValue) =>
                {
                    ((IconButton)bindable).IconMargin = (Thickness)newValue;
                }
            );

        public Thickness IconMargin
        {
            get { return (Thickness)GetValue(IconMarginProperty); }
            set
            {
                SetValue(IconMarginProperty, value);
                imgIcon.Margin = value;
            }
        }

        public IconButton()
        {
            InitializeComponent();
        }

        private void imgIcon_BindingContextChanged(object sender, EventArgs e)
        {
            if (addedAnimation || GestureRecognizers.Count == 0)
                return;

            var tapGesture = GestureRecognizers[0] as TapGestureRecognizer;
            if (tapGesture == null)
                return;

            tapGesture.Tapped += (tapsender, tape) =>
            {
                Device.BeginInvokeOnMainThread(async () => await tappedAnimation());
            };

            addedAnimation = true;
        }

        private async Task tappedAnimation()
        {
            BackgroundColor = Color.FromRgba(68, 68, 68, 70);
            await imgIcon.ScaleTo(0.8, 75);
            await imgIcon.ScaleTo(1.0, 75);
            BackgroundColor = Color.Transparent;
        }
    }
}

凹ます処理の前後に Content View 自体の背景色を適当な灰色にしています。
ポイントとして Alpha 値を設定して透過にすることで画面の背景色になじむようにしています。
本来はこの辺も BindableProperty にして公開した方がよかったかもしれませんが、まぁいいかなと。

使う画面.xaml
<control:IconButton
    HeightRequest="50"
    HorizontalOptions="Center"
    IconMargin="10"
    IconSource="{Binding Source=IconButtonSample.Images.Trash.png, Converter={StaticResource ImageSourceConverter}}"
    VerticalOptions="Center">
    <control:IconButton.GestureRecognizers>
        <TapGestureRecognizer Command="{Binding Path=DeleteCommand}" />
    </control:IconButton.GestureRecognizers>
</control:IconButton>

ImageSource を Converter 使っていますが、これは画像を埋め込みリソースにして PCL 側に置いているからです。
その辺も含めてこちらにまるごとサンプルを置いてありますので、ご自由にどうぞー。
Prism 使ってます。
github.com

あとは指が抑えている状態(Hold 時)にも色変えたいけど、とりあえず標準のヤツよりいいから満足です。

更新しました

shunsukekawai.hatenablog.com

Xamarin.Forms と Mobile Engagement でユーザー分析しちゃえ!

Xamarin Advent Calendar 2016 - Qiita "その1" 9日目の投稿です。

はい、ということでこんな状況の中、なんとか書きました。。


ホントは0時きっかりにアップしたかったけど、ご了承ください。

さて、Microsoft さんのイベントで使用したアプリケーションの開発をやった話の記事で簡単に説明しましたが、Azure の Mobile Engagement というサービスはとても楽しいサービスです。
shunsukekawai.hatenablog.com

本記事では Xamarin.Forms でどのように Mobile Engagement でどんなことができるのか、どう使用するかを解説をします。

Mobile Engagement でできること

リアルタイムのアクティブユーザー

こんな感じで今正にアクティブなユーザー数が表示されます。
f:id:ShunsukeKawai:20161102190000p:plain

どの画面がどれだけ使われているか

画面の起動時にコードを1行埋め込むことで、勝手にデータを蓄積してくれます。
f:id:ShunsukeKawai:20161102190017p:plain

どんな画面遷移を行っているか

どこからどこの画面に行ってるかよくわからん図で表示されます。
f:id:ShunsukeKawai:20161208225124p:plain

セッション時間はどのくらいか

どのくらいアクティブにアプリを使ってくれているのかが表示されます。
f:id:ShunsukeKawai:20161208225753p:plain

バイスはなにか

iOS(iPhone9,1とかなんなのか…)
f:id:ShunsukeKawai:20161208225228p:plain
Android は製造元を選択するとモデルまで表示されます。
f:id:ShunsukeKawai:20161208230027p:plain

OSはなにか

サポート対象OSを決める時に役に立ちそう。
f:id:ShunsukeKawai:20161208225325p:plain

どのアプリバージョンを使っているか

ちゃんとユーザーがバージョンアップしてくれてるかわかりますね。
f:id:ShunsukeKawai:20161208225357p:plain

画面サイズはなにか

どのサイズで動かされているかわかると色々対策できそうです。
f:id:ShunsukeKawai:20161208225512p:plain

アプリがクラッシュしている原因とその詳細

StackTrace 的なのも出てます。
f:id:ShunsukeKawai:20161208225632p:plain

と、まぁここに挙げたのは一部ですが、見てるだけでも酒の肴になりそうですね。

Xamarin.Forms に組み込む方法

ここからは Mobile Engagement をどうやってXamarin.Forms に組み込むかです。

Azure ポータルから Mobile Engagement のサービスを追加

f:id:ShunsukeKawai:20161201212016p:plain:w500

  • 対象プラットフォームを UWP、AndroidiOSを選択する

f:id:ShunsukeKawai:20161201215231p:plain:w500

  • その他設定はよしなに
  • 作成完了(3つのアプリが作成されます)

Mobile Engagement アプリはプラットフォームごとに作成する必要があります。
f:id:ShunsukeKawai:20161201215715p:plain:w500

Xamarin.Forms プロジェクトに Mobile Engagement 接続(Android 編)

基本的に以下のチュートリアルに沿って進めていけば大丈夫です。(人任せ)
もう Mobile Engagement 作成は済んでいるので、キーをコピーするところ以降ぐらいから。
Xamarin.Android 用 Azure Mobile Engagement の使用

  • 【注意1】NuGet から Microsoft.Azure.Engagement.Xamarin をインストールしたら勝手に作られるフォルダの対処

NuGet からインストールすると勝手にフォルダが作られてそこに Mobile Engagement 用のリソースが置かれます。
(おそらく Xamarin.Android 用だからかな)
そのためその状態でビルドすると以下の様なエラーが発生します。
f:id:ShunsukeKawai:20161208150417p:plain
↓犯人
f:id:ShunsukeKawai:20161208150802p:plain
↓該当するフォルダに移動します。(+になってるヤツを移動した)
f:id:ShunsukeKawai:20161208150959p:plain

  • 【注意2】using は Microsoft.Azure.Engagement.Xamarin だけでいい

MainActivity.cs の using は一つだけで大丈夫です。

  • 【注意3】MainActivity.cs に EngagementActivity の継承をすることは Xamarin.Forms ではできない(FormsAppCompatActivity をすでに継承しているため)

こっち側の手順でやる必要がある
Azure Mobile Engagement Android SDK の詳細なレポート オプション

Xamarin.Forms プロジェクトに Mobile Engagement 接続(iOS 編)

基本的に以下のチュートリアルに沿って進めていけば大丈夫です。(人任せ2)
もう Mobile Engagement 作成は済んでいるので、キーをコピーするところ以降から。
Xamarin.iOS 用 Azure Mobile Engagement の使用

Xamarin.Forms プロジェクトに Mobile Engagement 接続(UWP 編)

基本的に以下のチュートリアルに沿って進めていけば大丈夫です。(人任せ3)
もう Mobile Engagement 作成は済んでいるので、キーをコピーするところ以降から。

Windows ユニバーサル アプリの Azure Mobile Engagement の概要

  • 【注意1】UWP は他と NuGet のパッケージが違うから注意(~Xamarin ではない)
  • 【注意2】リンク先にも書いてありますが、NuGet は、Windows 10 UWP アプリケーションで SDK のリソースを自動的にコピーしません。 NuGet パッケージのインストール時に表示される手順 (readme.txt) に従って、手動で行う必要があります。

とあります。readme.txtの内容は以下の通り。はい。自分で作れっつーことですね。

NuGet does not automatically copy the SDK resources in your Windows 10 UWP application. You have to do it manually until the scaffolding feature is reintroduced. 
Here are the steps for a new integration:

* Open your File Explorer.
* Navigate to the following location: %USERPROFILE%\.nuget\packages\MicrosoftAzure.MobileEngagement\3.4.1\content\win81
* Drag and drop the "Resources" folder from the file explorer to the root of your project in Visual Studio.
* In Visual Studio select your project and activate the "Show All files" icon on top of the "Solution Explorer".
* Some files may not be included in the project. To import them at once right click on the "Resources" folder, "Exclude from project" then another right click on the "Resources" folder, "Include in project" to re-include the whole folder. All files from the "Resources" folder are now included in your project.

まとめ

この辺までの基本的な設定 + PCL に interface 作って各プラットフォーム側で処理を追加して PCL の MainPage.xaml.cs にアクティブにする処理入れたヤツを以下のリポジトリにアップしてあります。
github.com

Mobile Engagement 側の接続文字列を設定すればとりあえず動くと思います。
Push 通知したい場合は各プラットフォームのリンク先を参考に設定してみてください。(最後も人任せ)

それではお疲れ様でした。

VSTS で Team Foundation Version Control で Xamarin のソース管理をする際に package フォルダーを除外したい

かなりニッチな投稿です。

Visual Studio Team Services(VSTS)でソース管理を行う場合、以下の2つから選択できます。

正直 Git が今は主流だと思うのですが、ウチのチームは旧 Visual Source Safe(VSS)からの名残で Team Foundation Server(TFS) ベースの方を利用しています。

Xamarin.Forms のテンプレートで作ったプロジェクトを上記ソース管理に追加をすると、管理対象に package フォルダーを追加してしまいます。
f:id:ShunsukeKawai:20161118180510p:plain
もちろんこのチェックインからは除外することはできるのですが、永続的に対象から除外することは Visual Studio のメニューからはできなそうでした。
Xamarin が悪いのか、Visual Studio が悪いのか VSTS が悪いのか、それともほかの要因なのかわかりませんが。

チームで作業している場合、package フォルダーがソース管理されてしまうと、各作業者がビルドする時に NuGet からパッケージをダウンロードしてくる時に競合したり、読み取り専用になってるからエラーになったり、作業者が別のソースをチェックインしようとすると一緒にわんさか「こいつも変更しとるな?チェックインするけ?」と聞かれて毎回除外する必要がありとても面倒でした。

除外方法

ソリューションと同階層に以下のフォルダ/ファイルを置くだけ
・.tfignore ファイル
・.nuget フォルダ
 ・NuGet.config ファイル

.tfignore ファイルの中身

除外したいフォルダやファイルのパスを記載するだけ
今回なら

\package
NuGet.config ファイルの中身
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <solution>
    <add key="disableSourceControlIntegration" value="true" />
  </solution>
</configuration>

注意点1

Windowsエクスプローラー上だと、頭が「.(ドット)」のファイルが作れません。
そのため、適当なテキストファイルを作成してメモ帳で開く→名前を付けて保存→すべてのファイルを選択して「.tfignore」と命名して保存してやらないといけない。

注意点2

Windowsエクスプローラー上だと、頭が「.(ドット)」のフォルダーが作れません。
頭だけじゃなくお尻にも「.(ドット)」を付けてやると作れます。今回なら「.nuget.」で。

Tech Summit の資料・動画が公開されました

shunsukekawai.hatenablog.com
↑こちらで登壇した旨を記載しましたが、資料、動画が公開されました。

資料

docs.com

なにかご質問があれば Twitter かコメントで遠慮なくどうぞー!

【Xamarin 開発の真実】 Microsoft Tech Summit で登壇してきました!

11/1,2 で開催された Microsoft Tech Summit でテクニカルスポンサー枠として登壇してきました。

microsoft-events.jp

弊社は Mobile 系の開発や Windows 系の開発を推進してきた経緯もあり、今回 日本マイクロソフト株式会社 様より Xamarin でイベントアプリ開発のご依頼を受け、その流れで登壇をさせていただきました。

講演内容

【Xamarin 開発の真実】イベントアプリの中身、すべてお見せします

と名前負けしそうなタイトルとなりましたが、主な内容としては以下の通りです。

  • Xamarin とは
  • イベントアプリの構成
  • Xamarin と UX
  • Xamarin と認証
  • Xamarin と Push 通知 + α

f:id:ShunsukeKawai:20161102191047p:plain

それぞれどんなことを話したか簡単にまとめます。

Xamarin とは

このサイト見てくださいw
www.jmas.co.jp

イベントアプリの構成

イベントアプリの構成はこんな感じですー。ってそのままの話です。
f:id:ShunsukeKawai:20161102161853p:plain
サーバーは別の会社さんが開発をしていて、そこにアプリから接続してデータのやり取りをしています。

Xamarin と UX

標準だけでいけると思ってましたがやはりカスタマイズが必要になったので、Custom Renderer や Effects を利用しなきゃダメだよってお話し。
f:id:ShunsukeKawai:20161102172853p:plain
f:id:ShunsukeKawai:20161102172939p:plain
f:id:ShunsukeKawai:20161102173047p:plain

Xamarin と 認証

イベントアプリでは Microsoft アカウントでのサインインをする必要があります。
認証機能をどうやって作っているのか、デモを交えて説明しました。
f:id:ShunsukeKawai:20161102183406p:plain
f:id:ShunsukeKawai:20161102183414p:plain

詳細はここを参照ください。
blog.xamarin.com

Xamarin と Push 通知 + α

Azure Mobile Engagement を利用して Push 通知やユーザー状況の確認、クラッシュログなどが簡単に利用できるってお話し。
f:id:ShunsukeKawai:20161102183944p:plain
f:id:ShunsukeKawai:20161102184031p:plain
f:id:ShunsukeKawai:20161102184041p:plain
こんな感じでアクティブなユーザー数がリアルタイムで表示されます。
f:id:ShunsukeKawai:20161102190000p:plain
どの画面がよく使われているかをグラフィカルに表示してくれます。
f:id:ShunsukeKawai:20161102190017p:plain

詳細はここを参照ください。
azure.microsoft.com
※上記リンクは Xamarin.Android 用 & ちょっと古いので、変更が必要な箇所があります。

  • using は Microsoft.Azure.Engagement と Microsoft.Azure.Engagement.Activity じゃなくて Microsoft.Azure.Engagement.Xamarin だけでいい
  • 標準だと res フォルダーの中に Mobile Engagement 用の画像等が入るので、Resources の drawable フォルダ、layout フォルダに移動してあげないといけない

Azure Mobile Engagement を使ってみて

セッション中も参加者の方々にご協力いただき、アプリをアクティブにしていただいてリアルタイムに数がぐーんと上がるのをお見せしましたが、あんな機能を数行のコードで実現できてしまうのはホントにスゴイと思います。
Push 通知も簡単に管理できます!(デモでは失敗しましたが…)
マーケティングの方にすごい喜ばれる機能が盛りだくさんな感じです。
是非お試しください!!
azure.microsoft.com

Visual Studio から 作成した iOS の ipa をアプリケーションローダーに喰わせると ITMS-90023 が発生する

Xamarin で開発して iOS の AppStore にアップロードするための ipa を作成する際にアプリケーションローダーを使用してます。

Visual Studio の Xamarin.Forms のテンプレートから作ったプロジェクトをそのままアップロードすると以下のエラーが発生します。

ERROR ITMS-90023: "Missing required icon file. The bundle does not contain an app icon for iPad of exactly '167x167' pixels, in .png format for iOS versions supporting iPad Pro."

f:id:ShunsukeKawai:20161013161447p:plain

対応方法

Info.plist を XML エディター等で開きます。
f:id:ShunsukeKawai:20161013161924p:plain

その中のアイコンの指定が並んでいる箇所を選択して

<array>
	<string>Icon-72@2x.png</string>
	<string>Icon-72.png</string>
	<string>Icon@2x.png</string>
	<string>Icon.png</string>
	<string>Icon-60@2x.png</string>
	<string>Icon-76.png</string>
	<string>Icon-76@2x.png</string>
	<string>Default.png</string>
	<string>Default@2x.png</string>
	<string>Default-568h@2x.png</string>
	<string>Default-Portrait.png</string>
	<string>Default-Portrait@2x.png</string>
	<string>Icon-Small-50@2x.png</string>
	<string>Icon-Small-50.png</string>
	<string>Icon-Small-40.png</string>
	<string>Icon-Small-40@2x.png</string>
	<string>Icon-Small.png</string>
	<string>Icon-Small@2x.png</string>
</array>

の中に

	<string>Icon-83.5@2x.png</string>

を追加します。

あとは対応するサイズ(167x167)のアイコンを追加すればOKです。

注意点

Visual Studio 上で iOS のプロジェクトのプロパティを編集(プロビジョニングファイル等の設定を編集)して保存すると上記のplistの設定が勝手に消えますw
なので、申請用 ipa を作成する際にはちゃんと確認した方がいいかもですね。。

追記

田淵さん(@ytabuchi)に教えていただいた方法の方が楽ちんですね。
ytabuchi.hatenablog.com

(おそらく)世界一簡単にXamarin.Formsのアプリに特定の値でQRコードを生成して表示する方法

public MainPage()
{
    var QrValue = "QRコードにしたい文字列";

    var imgQr = new Image { Aspect = Aspect.AspectFit };
    imgQr.Source = ImageSource.FromUri(new Uri($"http://chart.apis.google.com/chart?cht=qr&chs=200x200&chld=H|0&chl={QrValue}"));

    Content = imgQr;
}

以上!


というのも寂しいので、ちょっと解説です。
みなさんご存知の通り、XamarinにはURLを画像ソースに指定する機能があります。
developer.xamarin.com

それを利用してGoogleQRコード生成のAPIを呼び出し、その結果を設定しているだけです。
QR Codes  |  Infographics  |  Google Developers
※Warning: This API is deprecated. Please use the actively maintained Google Charts API instead. See our deprecation policy for details.
 ということで現在、このAPIは非推奨のようなのでいつ使えなくなるかわかりません。
 また、非推奨になったことでライセンスもよくわかりませんでした。
 なので自己責任でお願いします

画像として返却してくれるAPIであればこれでなくてもなんでも大丈夫だと思います。

さらにおまけで…

こんな感じでイメージコントロールとインジケーターを重ねておいてイメージの読み込みが完了するまでぐるぐるが表示されるようにするといい感じですね。
(このAPIからのレスポンスが一瞬なのでぐるぐるが見えることはないかもしれません。。。)

public MainPage()
{
    var QrValue = "QRコードにしたい文字列";

    var imgQr = new Image { Aspect = Aspect.AspectFit };
    imgQr.Source = ImageSource.FromUri(new Uri($"http://chart.apis.google.com/chart?cht=qr&chs=200x200&chl={QrValue}"));

    var prgIndicator = new ActivityIndicator{
                                HorizontalOptions = LayoutOptions.CenterAndExpand,
                                VerticalOptions = LayoutOptions.CenterAndExpand
                            };

    imgQr.PropertyChanged += (sender, e) =>
    {
        if (e.PropertyName != nameof(imgQr.IsLoading))
            return;
        prgIndicator.IsRunning = imgQr.IsLoading;
        prgIndicator.IsVisible = imgQr.IsLoading;
    };

    Content = new Grid { Children = { prgIndicator, imgQr } };
}

Xamarin.FormsでUWPをReleaseビルドすると埋め込みリソースの画像が表示されない

以下の環境でUWPをReleaseビルドするとPCL側に配置した埋め込みリソースの画像が表示されませんでした。
・Xamarin.Forms 2.3.1.114
・VisualStudio 2015 Enterprise Update 3
・UWP対象ターゲット 10586


Xamarin.Formsで画像を表示する際に全プラットフォームで共通の画像を使いまわしたい場合、埋め込みリソースを使用する場合があると思います。
画像の設定方法については公式を参照ください。
developer.xamarin.com

んで、埋め込みリソースを使っていて、かつUWPのReleaseビルド(ビルドプロパティの「.Net ネイティブ ツール チェーンでコンパイルする」にチェックついている状態)で作成したアプリを実行するとデバッグコンソールに以下のエラーが出力されて画像が表示されませんでした。

例外がスローされました: 'System.IO.FileNotFoundException' (System.Private.Reflection.Core.dll の中)

んで、対症療法です。(解決方法と書いていいか自信ない…)
というか、こうやったらできた。

画像のパスを設定する際にAssemblyを引数に加えてやると表示されるようになりました。

var assembly = typeof(App).GetTypeInfo().Assembly;
img.Source = ImageSource.FromResource("XamarinApp1.Images.xamarin.png", assembly);

.Net Nativeさん怖い…

Androidでアプリアンインストール時の確認メッセージに「~は次のアプリの一部です」と出てくる

Android開発に慣れている人は当たり前のことなのかもしれませんが)
Xamarin.Formsでデフォルトの設定で作成したアプリをアンインストールをしようとすると、以下のように謎の確認メッセージがでてきます。
Android 5以降で確認)
f:id:ShunsukeKawai:20160808115816p:plain

変ですよね。
普通のアプリはこんな感じになります。
f:id:ShunsukeKawai:20160808115850p:plain


それで直し方。

アプリの名前なので、AndroidManifestの記載とMainActivity.csの記載を一致させると期待する結果になりました。
f:id:ShunsukeKawai:20160808120150p:plain
f:id:ShunsukeKawai:20160808120159p:plain

結果
f:id:ShunsukeKawai:20160808120354p:plain

上の例はテスト用の命名でしたが、通常の開発だとプロジェクトの命名にスペースは普通入れないけど、アプリの命名にはスペース入れるってケースは多いと思います。
その場合、MainActivity側を修正しないといけないって点がちょっとハマりました…
(MainActivityの記載はプロジェクト作成時に勝手に作成されて、かつ違いがスペースの有無だけなので…)

"ConvertResourcesCases" タスクが予期せずに失敗しました。

備忘

Xamarinでソリューションのファイルに日本語のパスが含まれているとAndroidのビルド時にタイトルのエラーが出る。
ユーザー名が日本語だと意図せず日本語パスが含まれる可能性もあるから要注意。

エラー "ConvertResourcesCases" タスクが予期せずに失敗しました。
System.IO.DirectoryNotFoundException: パス 'C:\Users\kawai\Documents\Visual Studio 2015\Projects\XamarinTestApp縺・XamarinApp\XamarinApp.Droid\obj\Debug\__library_projects__\Xamarin.Forms.Platform.Android\library_project_imports\res' の一部が見つかりませんでした。
場所 System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
場所 System.IO.FileSystemEnumerableIterator`1.CommonInit()
場所 System.IO.FileSystemEnumerableIterator`1..ctor(String path, String originalUserPath, String searchPattern, SearchOption searchOption, SearchResultHandler`1 resultHandler, Boolean checkHost)
場所 System.IO.Directory.EnumerateDirectories(String path, String searchPattern, SearchOption searchOption)
場所 Xamarin.Android.Tasks.ConvertResourcesCases.FixupResources(ITaskItem item, Dictionary`2 acwMap)
場所 Xamarin.Android.Tasks.ConvertResourcesCases.FixupResources(Dictionary`2 acwMap)
場所 Xamarin.Android.Tasks.ConvertResourcesCases.Execute()
場所 Microsoft.Build.BackEnd.TaskExecutionHost.Microsoft.Build.BackEnd.ITaskExecutionHost.Execute()
場所 Microsoft.Build.BackEnd.TaskBuilder.d__26.MoveNext() XamarinApp.Droid

Android only allows one navigation page on screen at a time

備忘

Xamarin.FormsのAndroid実行でタイトルのようなエラーが出たら、

だめ

public App()
{
    MainPage = new NavigationPage(new MediaPage());
}

だいじょうぶ

public App()
{
    MainPage = new MainPage();
}

UWPでカメラを使う際の注意点

UWPでカメラを使ったアプリを作る場合、一番簡単なのは CameraCaptureUI を使用した方法です。

細かい使い方はMSDN参照↓

CameraCaptureUI を使った写真とビデオのキャプチャ - Windows app development

この方法であればマニフェストファイルを「Webカメラ」の宣言も不要なままカメラを使えます。

ただ、この方法だと「アプリケーションのテンポラリーフォルダ(ms-appdata:///temp/)」に「CCapture.png」というファイル名でファイルがドンドン溜まっていきます。

なので、気付いたら保存した覚えのない写真がいつまでも残っちゃうなんてことがあるので要注意です。


ファイルにしたくない、細かい設定がしたい、とかの場合は MediaCapture を使用する方がよいみたいです。

MediaCapture を使った写真とビデオのキャプチャ - Windows app development

MSDN サブスクリプション ユーザーのXamarin登録方法

XamarinがVisualStudioユーザーに無料でついてくるようになりTLがその話題で持ち切りですが、実際にアクティベーションする方法がわかりづらく、また、どこにも書いてなかったのでメモ。


<前提>
Visual Studio Enterprise with MSDN のライセンスの場合です。
その他のサブスクリプションに関してはわかりません。


MSDNサブスクリプションのページへ行きます。
https://msdn.microsoft.com/ja-jp/subscriptions/manage


② アカウントタブの「Xamarin Studio (for OS X)」の「Register and download」を選択
f:id:ShunsukeKawai:20160406133449p:plain


③ Xamarinの登録ページに飛ぶので必要事項を記入して登録!!!
f:id:ShunsukeKawai:20160406154257p:plain

f:id:ShunsukeKawai:20160406133552p:plain
無料だーー!

GridView(ListView)のアイテムを選択した時に凹む動作をやめたい

UWPでGridViewもしくはListViewをただ単にパネルとしてボタンとかのコントロールを置いて使いたいケースがありました。

UWPから標準のGridViewItemはPressed時に押した箇所が凹むアニメーションが勝手に入ります。
それがちょっと用途からして邪魔だったので消しました。


MSDNのページからスタイルをコピーしてきて、、
GridViewItem スタイルとテンプレート - Windows app development

悪さをしそうなStoryboardを消してきます。
根本はこいつですね↓
PointerDownThemeAnimation

ついでにPointerOver時に枠に色が付くのとかも消しました。

こんな感じ↓
f:id:ShunsukeKawai:20160328203940g:plain

XAML

一応アイテムクリックが動くのか、アイテムの中のボタンは動くのかの確認用のイベント入れてます。

        <GridView IsItemClickEnabled="True" ItemClick="GridView_ItemClick">
            <!--動くGridViewItem-->
            <GridViewItem>
                <StackPanel Width="300" Height="300">
                    <StackPanel.Background>
                        <ImageBrush Stretch="Fill" ImageSource="Assets/saru.PNG"/>
                    </StackPanel.Background>
                    <TextBlock FontSize="30" Text="動くGridViewItem" />
                    <Button Click="Button_Click" Content="テストボタン" />
                </StackPanel>
            </GridViewItem>
            <!--動かないGridViewItem-->
            <GridViewItem Style="{StaticResource DisableEffectGridViewItemStyle}">
                <StackPanel Width="300" Height="300">
                    <StackPanel.Background>
                        <ImageBrush Stretch="Fill" ImageSource="Assets/saru.PNG"/>
                    </StackPanel.Background>
                    <TextBlock FontSize="30" Text="動かないGridViewItem" />
                    <Button Click="Button_Click" Content="テストボタン" />
                </StackPanel>
            </GridViewItem>
        </GridView>
Style
        <Style x:Key="DisableEffectGridViewItemStyle" TargetType="GridViewItem">
            <Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
            <Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
            <Setter Property="Background" Value="Transparent" />
            <Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseHighBrush}" />
            <Setter Property="TabNavigation" Value="Local" />
            <Setter Property="IsHoldingEnabled" Value="True" />
            <Setter Property="HorizontalContentAlignment" Value="Center" />
            <Setter Property="VerticalContentAlignment" Value="Center" />
            <Setter Property="Margin" Value="0,0,4,4" />
            <Setter Property="MinWidth" Value="{ThemeResource GridViewItemMinWidth}" />
            <Setter Property="MinHeight" Value="{ThemeResource GridViewItemMinHeight}" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="GridViewItem">
                        <Grid x:Name="ContentBorder"
                              Background="{TemplateBinding Background}"
                              BorderBrush="{TemplateBinding BorderBrush}"
                              BorderThickness="{TemplateBinding BorderThickness}">
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="CommonStates">
                                    <VisualState x:Name="Normal">
                                        <Storyboard>
                                            <PointerUpThemeAnimation Storyboard.TargetName="ContentPresenter" />
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="PointerOver" />
                                    <VisualState x:Name="Pressed" />
                                    <VisualState x:Name="Selected" />
                                    <VisualState x:Name="PointerOverSelected" />
                                    <VisualState x:Name="PressedSelected" />
                                </VisualStateGroup>
                                <VisualStateGroup x:Name="DisabledStates">
                                    <VisualState x:Name="Enabled" />
                                    <VisualState x:Name="Disabled">
                                        <Storyboard>
                                            <DoubleAnimation Duration="0"
                                                             Storyboard.TargetName="ContentBorder"
                                                             Storyboard.TargetProperty="Opacity"
                                                             To="{ThemeResource ListViewItemDisabledThemeOpacity}" />
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                                <VisualStateGroup x:Name="FocusStates">
                                    <VisualState x:Name="Unfocused" />
                                    <VisualState x:Name="Focused">
                                        <Storyboard>
                                            <DoubleAnimation Duration="0"
                                                             Storyboard.TargetName="FocusVisualWhite"
                                                             Storyboard.TargetProperty="Opacity"
                                                             To="1" />
                                            <DoubleAnimation Duration="0"
                                                             Storyboard.TargetName="FocusVisualBlack"
                                                             Storyboard.TargetProperty="Opacity"
                                                             To="1" />
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                                <VisualStateGroup x:Name="MultiSelectStates">
                                    <VisualState x:Name="MultiSelectDisabled">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="MultiSelectSquare" Storyboard.TargetProperty="Visibility">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="Visible" />
                                                <DiscreteObjectKeyFrame KeyTime="0:0:0.333" Value="Collapsed" />
                                            </ObjectAnimationUsingKeyFrames>
                                            <FadeOutThemeAnimation TargetName="MultiSelectSquare" />
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="MultiSelectEnabled">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="MultiSelectSquare" Storyboard.TargetProperty="Visibility">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="Visible" />
                                            </ObjectAnimationUsingKeyFrames>
                                            <FadeInThemeAnimation TargetName="MultiSelectSquare" />
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                                <VisualStateGroup x:Name="DataVirtualizationStates">
                                    <VisualState x:Name="DataAvailable" />
                                    <VisualState x:Name="DataPlaceholder">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PlaceholderTextBlock" Storyboard.TargetProperty="Visibility">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="Visible" />
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PlaceholderRect" Storyboard.TargetProperty="Visibility">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="Visible" />
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                                <VisualStateGroup x:Name="ReorderHintStates">
                                    <VisualState x:Name="NoReorderHint" />
                                    <VisualState x:Name="BottomReorderHint">
                                        <Storyboard>
                                            <DragOverThemeAnimation Direction="Bottom"
                                                                    ToOffset="{ThemeResource GridViewItemReorderHintThemeOffset}"
                                                                    TargetName="ContentBorder" />
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="TopReorderHint">
                                        <Storyboard>
                                            <DragOverThemeAnimation Direction="Top"
                                                                    ToOffset="{ThemeResource GridViewItemReorderHintThemeOffset}"
                                                                    TargetName="ContentBorder" />
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="RightReorderHint">
                                        <Storyboard>
                                            <DragOverThemeAnimation Direction="Right"
                                                                    ToOffset="{ThemeResource GridViewItemReorderHintThemeOffset}"
                                                                    TargetName="ContentBorder" />
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="LeftReorderHint">
                                        <Storyboard>
                                            <DragOverThemeAnimation Direction="Left"
                                                                    ToOffset="{ThemeResource GridViewItemReorderHintThemeOffset}"
                                                                    TargetName="ContentBorder" />
                                        </Storyboard>
                                    </VisualState>
                                    <VisualStateGroup.Transitions>
                                        <VisualTransition GeneratedDuration="0:0:0.2" To="NoReorderHint" />
                                    </VisualStateGroup.Transitions>
                                </VisualStateGroup>
                                <VisualStateGroup x:Name="DragStates">
                                    <VisualState x:Name="NotDragging" />
                                    <VisualState x:Name="Dragging">
                                        <Storyboard>
                                            <DoubleAnimation Duration="0"
                                                             Storyboard.TargetName="ContentBorder"
                                                             Storyboard.TargetProperty="Opacity"
                                                             To="{ThemeResource ListViewItemDragThemeOpacity}" />
                                            <DragItemThemeAnimation TargetName="ContentBorder" />
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="DraggingTarget">
                                        <Storyboard>
                                            <DropTargetItemThemeAnimation TargetName="ContentBorder" />
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="MultipleDraggingPrimary">
                                        <Storyboard>
                                            <DoubleAnimation Duration="0"
                                                             Storyboard.TargetName="MultiArrangeOverlayBackground"
                                                             Storyboard.TargetProperty="Opacity"
                                                             To="1" />
                                            <DoubleAnimation Duration="0"
                                                             Storyboard.TargetName="MultiArrangeOverlayText"
                                                             Storyboard.TargetProperty="Opacity"
                                                             To="1" />
                                            <DoubleAnimation Duration="0"
                                                             Storyboard.TargetName="ContentBorder"
                                                             Storyboard.TargetProperty="Opacity"
                                                             To="{ThemeResource ListViewItemDragThemeOpacity}" />
                                            <FadeInThemeAnimation TargetName="MultiArrangeOverlayBackground" />
                                            <FadeInThemeAnimation TargetName="MultiArrangeOverlayText" />
                                            <DragItemThemeAnimation TargetName="ContentBorder" />
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="MultipleDraggingSecondary">
                                        <Storyboard>
                                            <FadeOutThemeAnimation TargetName="ContentBorder" />
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="DraggedPlaceholder">
                                        <Storyboard>
                                            <FadeOutThemeAnimation TargetName="ContentBorder" />
                                        </Storyboard>
                                    </VisualState>
                                    <VisualStateGroup.Transitions>
                                        <VisualTransition GeneratedDuration="0:0:0.2" To="NotDragging" />
                                    </VisualStateGroup.Transitions>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                            <ContentPresenter x:Name="ContentPresenter"
                                              Margin="{TemplateBinding Padding}"
                                              HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                              ContentTransitions="{TemplateBinding ContentTransitions}" />
                            <TextBlock x:Name="PlaceholderTextBlock"
                                       Margin="{TemplateBinding Padding}"
                                       AutomationProperties.AccessibilityView="Raw"
                                       Foreground="{x:Null}"
                                       IsHitTestVisible="False"
                                       Text="Xg"
                                       Visibility="Collapsed" />
                            <Rectangle x:Name="PlaceholderRect"
                                       Fill="{ThemeResource ListViewItemPlaceholderBackgroundThemeBrush}"
                                       Visibility="Collapsed" />
                            <Rectangle x:Name="MultiArrangeOverlayBackground"
                                       Grid.ColumnSpan="2"
                                       Fill="{ThemeResource ListViewItemDragBackgroundThemeBrush}"
                                       IsHitTestVisible="False"
                                       Opacity="0" />
                            <Rectangle x:Name="BorderRectangle"
                                       IsHitTestVisible="False"
                                       Opacity="0"
                                       Stroke="{ThemeResource SystemControlHighlightListAccentLowBrush}"
                                       StrokeThickness="2" />
                            <Border x:Name="MultiSelectSquare"
                                    Width="20"
                                    Height="20"
                                    Margin="0,2,2,0"
                                    HorizontalAlignment="Right"
                                    VerticalAlignment="Top"
                                    Background="{ThemeResource SystemControlBackgroundChromeMediumBrush}"
                                    Visibility="Collapsed">
                                <FontIcon x:Name="MultiSelectCheck"
                                          FontFamily="{ThemeResource SymbolThemeFontFamily}"
                                          FontSize="16"
                                          Foreground="{ThemeResource SystemControlForegroundBaseMediumHighBrush}"
                                          Glyph="&#xE73E;"
                                          Opacity="0" />
                            </Border>
                            <Rectangle x:Name="FocusVisualWhite"
                                       IsHitTestVisible="False"
                                       Opacity="0"
                                       Stroke="{ThemeResource SystemControlForegroundAltHighBrush}"
                                       StrokeDashArray="1.0, 1.0"
                                       StrokeDashOffset="1.5"
                                       StrokeEndLineCap="Square"
                                       StrokeThickness="2" />
                            <Rectangle x:Name="FocusVisualBlack"
                                       IsHitTestVisible="False"
                                       Opacity="0"
                                       Stroke="{ThemeResource SystemControlForegroundBaseHighBrush}"
                                       StrokeDashArray="1.0, 1.0"
                                       StrokeDashOffset="0.5"
                                       StrokeEndLineCap="Square"
                                       StrokeThickness="2" />
                            <TextBlock x:Name="MultiArrangeOverlayText"
                                       Grid.ColumnSpan="2"
                                       Margin="18,9,0,0"
                                       AutomationProperties.AccessibilityView="Raw"
                                       FontFamily="{ThemeResource ContentControlThemeFontFamily}"
                                       FontSize="26.667"
                                       Foreground="{ThemeResource ListViewItemDragForegroundThemeBrush}"
                                       IsHitTestVisible="False"
                                       Opacity="0"
                                       Text="{Binding RelativeSource={RelativeSource TemplatedParent},
                                                      Path=TemplateSettings.DragItemsCount}"
                                       TextTrimming="WordEllipsis"
                                       TextWrapping="Wrap" />
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

Slackでよく使うショートカットとか

メモメモ

Alt + クリック : 既読→未読
入力領域で↑  : 直近の自分の投稿を再編集する
``` で囲む   : 囲ったところを引用
> (半角)    : その行を引用