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

しっぽを追いかけて

ぐるぐるしながら考えています

Unity と猫の話題が中心   掲載内容は個人の私見であり、所属組織の見解ではありません

Xamarin を 1.3 以上に更新したら前回のコードが動かなくなった!

Xamarin Windows ランタイムアプリ iOS C# Windows Phone

詳しくは P3PPP さんの下記の Qiita 記事で紹介されていますが、ついに Xamarin にも Style や Trigger などが追加されたようですね!

ちょっと未来のXamarin.Formsを試す(1.3.0 Technology Preview) - Qiita

さっそく Xamarin.Forms を Nuget で更新して上記の情報を頼りに修正してみると・・・

f:id:matatabi_ux:20150113224448p:plain

うごかないー!!

Xamarin にはありがちな仕様変更なので、あらためて対応するしかありません

まずは共通コード側の Xamarin.Forms のコードは下記のように修正します

/// <summary>
/// アプリケーション基底クラス
/// </summary>
public class AppBase : Application
{
}

AppBase.cs と

/// <summary>
/// 共通 アプリケーションクラス
/// </summary>
public partial class App : AppBase
{
    /// <summary>
    /// アプリケーションクラス参照
    /// </summary>
    public static readonly App Current;

    /// <summary>
    /// アプリ内で管理するモジュールのコンテナ
    /// </summary>
    public static readonly UnityContainer Container = new UnityContainer();

    /// <summary>
    /// コンストラクタ
    /// </summary>
    static App()
    {
        Current = new App();
    }

    /// <summary>
    /// コンストラクタ
    /// </summary>
    private App()
    {
        // Prism.Mvvm.Xamarin アセンブリを読み込み可能にするおまじない
        var autoWired = ViewModelLocator.AutoWireViewModelProperty.DefaultValue;
    }

    /// <summary>
    /// アプリケーション初期処理
    /// </summary>
    public void Initialize()
    {
        // 画面状態監視サービス を DI コンテナに登録
        Container.RegisterType<IPageStateDetectService, PageStateDetectService>(new ContainerControlledLifetimeManager());

        // ViewModel をインスタンス化するデフォルトメソッドを指定します
        ViewModelLocationProvider.SetDefaultViewModelFactory((type) => Container.Resolve(type));

        App.Container.RegisterType<NumberItemViewModel>(new InjectionProperty("Number", 0));

        // テーマリソース読み込み
        App.Container.Resolve<IResources>().Load();

        this.MainPage = new TopPage();
    }
}

App.xaml.cs を起動シーケンスの変更に合わせて調整し

/// <summary>
/// リソース定義 View の基底クラス
/// </summary>
public abstract class ResourcesBase : ContentView, IResources
{
    /// <summary>
    /// リソースを読み込む
    /// </summary>
    public void Load()
    {
        if (App.Current.Resources == null)
        {
            App.Current.Resources = new ResourceDictionary();
        }

        // AppResources にテーマリソースを上書き・追加します
        foreach (var resource in this.Resources)
        {
            if (App.Current.Resources.ContainsKey(resource.Key))
            {
                App.Current.Resources[resource.Key] = resource.Value;
            }
            else
            {
                App.Current.Resources.Add(resource.Key, resource.Value);
            }
        }
    }
}

ResourcesBase.cs も少し修正 こちらは Null 例外対応のみですが

お次に各プラットフォームの対応

public class Application
{
    // This is the main entry point of the application.
    static void Main(string[] args)
    {
        // if you want to use a different Application Delegate class from "AppDelegate"
        // you can specify it here.
        UIApplication.Main(args, null, "AppDelegate");
    }
}

iOS の Application クラスはデフォルトのコードに戻します

public partial class App : Application
{
    /// <summary>
    /// Provides easy access to the root frame of the Phone Application.
    /// </summary>
    /// <returns>The root frame of the Phone Application.</returns>
    public static PhoneApplicationFrame RootFrame { get; private set; }

    /// <summary>
    /// Constructor for the Application object.
    /// </summary>
    public App()
    {
        // Global handler for uncaught exceptions.
        UnhandledException += Application_UnhandledException;

        DisplayProperties.AutoRotationPreferences = DisplayOrientations.Landscape | DisplayOrientations.LandscapeFlipped | DisplayOrientations.Portrait | DisplayOrientations.PortraitFlipped;

        // Standard XAML initialization
        InitializeComponent();

        // Phone-specific initialization
        InitializePhoneApplication();

        // Language display initialization
        InitializeLanguage();

        ~ 中略 ~
    }
}

Windows Phone の方も同様にデフォルトコードに戻して

/// <summary>
/// アプリケーション代理クラス
/// </summary>
[Register("AppDelegate")]
public partial class AppDelegate : FormsApplicationDelegate
{
    /// <summary>
    /// 起動完了時の処理
    /// </summary>
    /// <param name="app">アプリケーション</param>
    /// <param name="options">オプション指定</param>
    /// <returns></returns>
    public override bool FinishedLaunching(UIApplication app, NSDictionary options)
    {
        Forms.Init();

        // テーマリソースを登録
        App.Container.RegisterType<IResources, ThemeResources>(new ContainerControlledLifetimeManager());

        // アプリケーション初期処理
        App.Current.Initialize();

        LoadApplication(App.Current);

        return base.FinishedLaunching(app, options);
    }
}

iOS の AppDelegate は Forms.Init から LoadApplication の間に初期化処理を挟みます

/// <summary>
/// アプリケーション代理クラス(メイン画面)
/// </summary>
public partial class MainPage : FormsApplicationPage
{
    /// <summary>
    /// コンストラクタ
    /// </summary>
    public MainPage()
    {
        InitializeComponent();
        Forms.Init();

        // テーマリソースを登録
        XamarinUnityInjection.App.Container.RegisterType<IResources, ThemeResources>(new ContainerControlledLifetimeManager());

        // アプリケーション初期処理
        XamarinUnityInjection.App.Current.Initialize();

        LoadApplication(XamarinUnityInjection.App.Current);
    }
}

Windows Phone の MainPage.xaml.cs も同様に

これで何とか元通りに動くようになりました・・・こういった仕様変更が頻繁にあるとちょっと面倒ですね がんばってついていかないと;

まぁ今までがちょっとアーキテクチャ的に微妙だったのでテコ入れが入ったってことで今後はそれほど大きな変更はないと思いますが!