読者です 読者をやめる 読者になる 読者になる

ディーバ Blog

大阪発 C#の会社、株式会社ディーバの Blog です。

例外 Foundation.You_Should_Not_Call_base_In_This_Method

Xamarin で開発していると「Foundation.You_Should_Not_Call_base_In_This_Method: Exception of type ‘Foundation.You_Should_Not_Call_base_In_This_Method’ was thrown.」という例外とメッセージが出ることがあります。

名前の通り、base クラスのメソッドを呼び出してはいけません。UITableViewSource など override して使っているメソッドで、エディターが自動挿入した base クラスへの呼び出しがないか確認してみてください。

Xamarin + MvvmCross などの環境の場合、ピンポイントで例外発生場所を示してくれないときがあります。TableViewSource の場合、CanEditRow メソッドなどが base クラスのメソッドをつかえません。

Android カメラ API でフロント/バックカメラ画像を同時に表示

Android のフロント/バックカメラを同時にアクセスする方法です。結論は Android 4 ではできたようで 5.0 (Lollipop) からできなくなっている(?)ようです。

Android の カメラ API は、新旧2種類あります。

Camera

旧 Camera API では、実際にされている方がいて、同時に両方のカメラ映像を表示するデモとソースコードが公開されています。

www.youtube.com

bitbucket.org

ただし、Android 5 で実行すると Camera.Open のところで Fail to connect to camera service の例外が出ます。Bitbucket のプロジェクトの Issue にそのような コメント もあります。

Camera2

新しい camera2 API で試してみると、CmeraManage.openCamera で2台目にアクセスすると MAX_CAMERAS_IN_USE エラーが発生します。

複数の Android 端末で試しましたが同じ結果。もしかすると機種によっては可能なものもあるかもしれませんが、Android OS で拒否されているのかも。

Galaxy シリーズには、デュアルカメラアプリがあり、標準カメラアプリではもちろん同時撮影できますが、試したコードは同様にエラーとなりました。

操作ガイド

MvvmCross + Xamarin.iOS で NavigationBar 付きの modal 画面を使う

MvvmCross で画面遷移は ViewModel 側で ShowViewModel<SecondViewModel>() のように ShowViewModel メソッドを使います。

github.com

このとき iOS アプリで modal 画面として表示する方法です。

IMvxModalIosView の実装

View 側のクラスは IMvxModalIosView を実装します。

public partial class SecondView : MvxViewController<SecondViewModel>, IMvxModalIosView<SecondViewModel>
{
    public SecondView(IntPtr handle) : base(handle)
    {
    }
}

MvxIosViewPresenter のカスタマイズ

デフォルトの Presenter クラスを override することで、iOS の画面遷移・表示をカスタマイズできます。modal 表示をサポートするクラスが用意されているので、これを使います。

AppDelegate.cs にある次の部分を修正します。

var setup = new Setup(this, Window);
setup.Initialize();

単に modal を使う場合は、MvxModalSupportIosViewPresenter クラスを使います。この場合は modal 画面の NavigationController は null になります。

var presenter = new MvxModalSupportIosViewPresenter(this, Window);
var setup = new Setup(this, presenter);
setup.Initialize();

NavigationBar を付けて modal 画面を表示したい場合は、MvxModalNavSupportIosViewPresenter クラスを使います。

var presenter = new MvxModalNavSupportIosViewPresenter(this, Window);
var setup = new Setup(this, presenter);
setup.Initialize();

何をしているかはソースコードを読むしかありません。

github.com

Xamarin.Android で interface を実装するとき Handle と Dispose の実装

Xamarin.Android で Listener などの interface を実装しようとしたとき、Handle プロパティと Dispose メソッドを実装する必要があります。

class SampleListener : AppBarLayout.IOnOffsetChangedListener
{
    public IntPtr Handle => throw new NotImplementedException();

    public void Dispose()
    {
        throw new NotImplementedException();
    }

    public void OnOffsetChanged(AppBarLayout appBarLayout, int verticalOffset)
    {
        throw new NotImplementedException();
    }
}

これは Java.Lang.Object を継承すれば解決します。

class SampleListener : Java.Lang.Object, AppBarLayout.IOnOffsetChangedListener
{
    public void OnOffsetChanged(AppBarLayout appBarLayout, int verticalOffset)
    {
        throw new NotImplementedException();
    }
}

「エラー: error MT1108: Could not find developer tools for this 10.2.1 (14D27) device.」でアプリが起動しない

Xamarin (Visual Studio) で次のようなエラーが出る場合の対処です。

起動に失敗しました。アプリ ‘AppName’‘DeviceName’ で起動できませんでした。 エラー: error MT1108: Could not find developer tools for this 10.2.1 (14D27) device. Please ensure you are using a compatible Xcode version and then connect this device to Xcode to install the development support files.

  • アプリの SDK バージョンが iOS 10.1
  • デバッグ対象のデバイスが iOS 10.2
  • Xcode のサポートしているバージョンが iOS 10.1

というように、アプリの配置先の方が新しいバージョンだと起こるようです。

対処は、最新の Xcode をインストールして、アプリの SDK バージョンを対象のデバイスと合わせます。

※ このエラーは Xcode によるもので Xamarin とは直接関係しません。

Azure Web App で ASP.NET MVC Web アプリの初回アクセスが遅い

ASP.NET MVC Web アプリケーションを Azure Web App へ発行した場合、初回の表示が非常に遅い場合、次の設定を見直すと高速化できます。

常時接続をオン

Azure ポータルで、Web App の「アプリケーション設定」にある「常時接続」をオンにします。

f:id:jz5_diva:20170227140040p:plain

「Web アプリを毎回読み込む必要があることを示します。既定では、Web アプリはアイドルになった後でアンロードされます。この Web アプリで実行されている継続的な Web ジョブがある場合は、このオプションを有効にすることをお勧めします」とのこと。

IIS の開始モード (startMode) 設定の “AlwaysRunning” が、この常時接続 (Always On) にあたるようです。

ファイル発行オプションでプリコンパイルする

Visual Studio の発行の「設定」で、ファイル発行オプションの「発行中にプリコンパイルする」にチェックします。また、「構成」ウィンドウの「プリコンパイル済みサイトを更新可能にする」のチェックを外します。

f:id:jz5_diva:20170227135911p:plain

f:id:jz5_diva:20170227135914p:plain

以上で、発行時に少し時間がかかりますが、初回アクセスの時間が早くなっているはずです。ただし、View のみの更新(cshtml ファイルのみを差し替え)などはできなくなります。

※ 「App_Dataフォルダーのファイルを除外する」は、発行時に App_Data フォルダーの内容を追加や更新したりしません。必要に応じてオン・オフしてください。

発行先の追加ファイルを削除する

プリコンパイルせず発行したことがある場合、プリコンパイルしたアプリの実行に不要なフォルダーがサーバーに残っているため「The directory ‘/App_GlobalResources/’ is not allowed because the application is precompiled」といったエラーが発生するかもしれません。

その場合、ファイル発行オプションの「発行先の追加ファイルを削除する」をチェックして発行すれば、プロジェクトにないファイル等は削除され、エラーが起きません。アプリでサーバーに直接ファイルを作っている場合は、それらのファイルも削除されるので注意してください。

iTextSharp で外字を PDF に出力

少しだけ iTextSharp と日本語外字を扱ったのでメモ。

DirectContent を使う場合

外字ファイルを指定した BaseFont オブジェクトを生成します。DirectContent.ShowTextAligned メソッドを使うと自由な位置にテキストを出力できますが、指定できるフォントがひとつのため外字しか出力できません。

外字ファイル EUDC.TTE をコピーして拡張子を TTF へリネームすると扱えるようです。

TechPress » iTextSharpで外字を利用する方法 を参考にしました。

//using iTextSharp.text;
//using iTextSharp.text.pdf;
//using System;
//using System.IO;
//using System.Linq;
//using System.Text;

private static void Sample1()
{
    var eudcPath = "EUDC.TTF";
    File.Copy(@"c:\Windows\Fonts\EUDC.TTE", eudcPath, true); // 外字ファイルをコピー・リネーム
    var eudcBaseFont = BaseFont.CreateFont(eudcPath, BaseFont.IDENTITY_H, true);

    var doc = new Document();
    var writer = PdfWriter.GetInstance(doc, new FileStream("sample1.pdf", FileMode.Create));
    doc.Open();

    var cb = writer.DirectContent;
    cb.BeginText();
    cb.SetFontAndSize(eudcBaseFont, 12);
    cb.ShowTextAligned(PdfContentByte.ALIGN_LEFT, "外字テキスト", 100, 100, 0);
    cb.EndText();

    doc.Close();
}

Phrase を使う場合

通常のテキストと外字テキストでフォントの指定を変えた Phrase オブジェクトを生成します。

ゆめみるうみそら 夢見海空 » itextSharpで日本語外字の対応 を参考にしました(ほとんどそのままです)。

//using iTextSharp.text;
//using iTextSharp.text.pdf;
//using System;
//using System.IO;
//using System.Linq;
//using System.Text;

private static void Sample2()
{
    var normalFont = new Font(BaseFont.CreateFont(@"c:\Windows\Fonts\msgothic.ttc,0", BaseFont.IDENTITY_H, true), 12, Font.NORMAL, new BaseColor(0, 0, 0));

    var eudcPath = "EUDC.TTF";
    File.Copy(@"c:\Windows\Fonts\EUDC.TTE", eudcPath, true); // 外字ファイルをコピー・リネーム
    var eudcFont = new Font(BaseFont.CreateFont(eudcPath, BaseFont.IDENTITY_H, true), 12, Font.NORMAL, new BaseColor(0, 0, 0));

    var doc = new Document();
    var writer = PdfWriter.GetInstance(doc, new FileStream("sample2.pdf", FileMode.Create));
    doc.Open();

    var p = CreatePhrase("外字を含むテキスト", normalFont, eudcFont);
    doc.Add(p);

    doc.Close();
}

private static Phrase CreatePhrase(string s, Font normalFont, Font eudcFont)
{
    var p = new Phrase();
    foreach (var c in s)
    {
        var buf = Encoding.GetEncoding("Shift_JIS").GetBytes(c.ToString());
        var code = BitConverter.ToUInt16(buf.Reverse().ToArray(), 0);
        var font = (code >= 0xF000 && code <= 0xFFFC) ? eudcFont : normalFont;
        p.Add(new Chunk(c, font));
    }
    return p;
}

フォント フォルダーをエクスプローラーで開く

フォントフォルダー(通常 c:\Windows\Fonts)をエクスプローラーで開くと、特殊な表示になってしまい、実ファイルを参照できません。

ファイルを参照したい場合、パスを \\コンピューター名\c$\Windows\Fonts としてアクセスするテクニックがあるようです。