Xamarin ネイティブ プロジェクトでの Xamarin.Forms
通常、 Xamarin.Forms アプリケーションには ContentPage
から派生した 1 つ以上のページが含まれており、これらのページは .NET Standard ライブラリ プロジェクトまたは共有プロジェクト内のすべてのプラットフォームで共有されます。 ただし、ネイティブ フォームを使用すれば、ContentPage
から派生したページをネイティブ Xamarin.iOS、Xamarin.Android、UWP アプリケーションに直接追加できます。 ネイティブ プロジェクトで .NET Standard ライブラリ プロジェクトまたは共有プロジェクトから ContentPage
から派生したページを使用する場合と比較して、ネイティブ プロジェクトにページを直接追加する利点は、ページをネイティブ ビューで拡張できることです。 その後、ネイティブ ビューは、x:Name
を使用して XAML で名前を付け、コードビハインドから参照できます。 ネイティブ ビューの詳細については、「ネイティブ フォーム」をご覧ください。
ネイティブ プロジェクトで Xamarin.FormsContentPage
から派生したページを使用するプロセスは次のとおりです。
- Xamarin.Forms NuGet パッケージをネイティブ プロジェクトに追加します。
ContentPage
から派生したページと依存関係をネイティブ プロジェクトに追加します。Forms.Init
メソッドを呼び出します。ContentPage
から派生したページのインスタンスを構築し、iOS 用のCreateViewController
、Android 用のCreateSupportFragment
、または UWP 用のCreateFrameworkElement
のいずれかの拡張メソッドを使用して、適切なネイティブ型に変換します。- ネイティブ ナビゲーション API を使用して、
ContentPage
から派生したページのネイティブ型表現に移動します。
ネイティブ プロジェクトで ContentPage
から派生したページを構築する前に、Forms.Init
メソッドを呼び出して Xamarin.Forms を初期化する必要があります。 これを行うタイミングの選択は、主に、アプリケーション フローで最も便利なタイミングによって異なります。これは、アプリケーションの起動時、または ContentPage
から派生したページが構築される直前の場合もあります。 この記事と付属のサンプル アプリケーションでは、Forms.Init
メソッドはアプリケーションの起動時に呼び出されます。
Note
NativeForms サンプル アプリケーション ソリューションには、Xamarin.Forms プロジェクトが含まれていません。 代わりに、Xamarin.iOS プロジェクト、Xamarin.Android プロジェクト、UWP プロジェクトで構成されています。 各プロジェクトは、ネイティブ フォームを使用して ContentPage
から派生したページを使用するネイティブ プロジェクトです。 ただし、ネイティブ プロジェクトで .NET Standard ライブラリ プロジェクトまたは共有プロジェクトから ContentPage
派生のページを使用できない理由はありません。
ネイティブ フォームを使用する場合、DependencyService
、MessagingCenter
、データ バインディング エンジンなどの Xamarin.Forms 機能はすべて引き続き機能します。 ただし、ページ ナビゲーションはネイティブ ナビゲーション API を使用して実行する必要があります。
iOS
iOS では、通常、AppDelegate
クラスの FinishedLaunching
オーバーライドは、アプリケーション起動関連のタスクを実行する場所です。 アプリケーションの起動後に呼び出され、通常はメイン ウィンドウとビュー コントローラーを構成するためにオーバーライドされます。 次のコード例は、サンプル アプリケーションの AppDelegate
クラスを示しています。
[Register("AppDelegate")]
public class AppDelegate : UIApplicationDelegate
{
public static AppDelegate Instance;
UIWindow _window;
AppNavigationController _navigation;
public static string FolderPath { get; private set; }
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
Forms.Init();
// Create app-level resource dictionary.
Xamarin.Forms.Application.Current = new Xamarin.Forms.Application();
Xamarin.Forms.Application.Current.Resources = new MyDictionary();
Instance = this;
_window = new UIWindow(UIScreen.MainScreen.Bounds);
UINavigationBar.Appearance.SetTitleTextAttributes(new UITextAttributes
{
TextColor = UIColor.Black
});
FolderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData));
NotesPage notesPage = new NotesPage()
{
// Set the parent so that the app-level resource dictionary can be located.
Parent = Xamarin.Forms.Application.Current
};
UIViewController notesPageController = notesPage.CreateViewController();
notesPageController.Title = "Notes";
_navigation = new AppNavigationController(notesPageController);
_window.RootViewController = _navigation;
_window.MakeKeyAndVisible();
notesPage.Parent = null;
return true;
}
// ...
}
FinishedLaunching
メソッドは、次のタスクを実行します。
- Xamarin.Forms は、メソッドを
Forms.Init
呼び出すと初期化されます。 - 新しい
Xamarin.Forms.Application
オブジェクトが作成され、そのアプリケーション レベルのリソース ディクショナリが XAML で定義されているResourceDictionary
に設定されます。 AppDelegate
クラスへの参照は、static
Instance
フィールドに格納されます。 これは、他のクラスがAppDelegate
クラスで定義されたメソッドを呼び出すためのメカニズムを提供するためです。- ネイティブ iOS アプリケーションのビューのメイン コンテナーである
UIWindow
が作成されます。 FolderPath
プロパティは、メモ データが保存されるデバイス上のパスに初期化されます。NotesPage
オブジェクトが作成されます。これは XAML で定義された Xamarin.FormsContentPage
から派生したページであり、その親は以前に作成したXamarin.Forms.Application
オブジェクトに設定されています。NotesPage
オブジェクトは、CreateViewController
拡張メソッドを使用してUIViewController
に変換されます。UIViewController
のTitle
プロパティが設定され、UINavigationBar
に表示されます。- 階層ナビゲーションを管理するために
AppNavigationController
が作成されます。 これは、UINavigationController
から派生するカスタム ナビゲーション コントローラー クラスです。AppNavigationController
オブジェクトはビュー コントローラーのスタックを管理し、コンストラクターに渡されるUIViewController
は、AppNavigationController
が読み込まれるときに最初に表示されます。 AppNavigationController
オブジェクトはUIWindow
の最上位UIViewController
として設定され、UIWindow
はアプリケーションのキー ウィンドウとして設定され、表示されます。- メモリ リークを防ぐために、
NotesPage
オブジェクトのParent
プロパティはnull
に設定されます。
FinishedLaunching
メソッドが実行されると、次のスクリーンショットに示すように、Xamarin.FormsNotesPage
クラスで定義されている UI が表示されます。
重要
ContentPage
から派生したページはすべて、ページの Parent
プロパティが Application
オブジェクトに設定されている場合、アプリケーションレベルの ResourceDictionary
で定義されているリソースを使用できます。
NotesPage
分離コードで次のイベント ハンドラーが実行されます。
void OnNoteAddedClicked(object sender, EventArgs e)
{
AppDelegate.Instance.NavigateToNoteEntryPage(new Note());
}
static
AppDelegate.Instance
フィールドを使用すると、次のコード例に示すように、AppDelegate.NavigateToNoteEntryPage
メソッドを呼び出すことができます。
public void NavigateToNoteEntryPage(Note note)
{
NoteEntryPage noteEntryPage = new NoteEntryPage
{
BindingContext = note,
// Set the parent so that the app-level resource dictionary can be located.
Parent = Xamarin.Forms.Application.Current
};
var noteEntryViewController = noteEntryPage.CreateViewController();
noteEntryViewController.Title = "Note Entry";
_navigation.PushViewController(noteEntryViewController, true);
noteEntryPage.Parent = null;
}
NavigateToNoteEntryPage
メソッドは、Xamarin.FormsContentPage
から派生したページを CreateViewController
拡張メソッドを使用して UIViewController
に変換し、UIViewController
の Title
プロパティを設定します。 その後、UIViewController
は、PushViewController
メソッドによって AppNavigationController
にプッシュされます。 そのため、次のスクリーンショットに示すように、Xamarin.FormsNoteEntryPage
クラスで定義されている UI が表示されます。
NoteEntryPage
が表示されると、戻るナビゲーションにより AppNavigationController
から NoteEntryPage
クラスの UIViewController
がポップされ、ユーザーは NotesPage
クラスの UIViewController
に戻ります。 ただし、iOS ネイティブ ナビゲーション スタックから UIViewController
をポップしても、UIViewController
とアタッチされた Page
オブジェクトは自動的に破棄されません。 したがって、AppNavigationController
クラスは、逆方向のナビゲーションでビュー コントローラーを破棄するために、PopViewController
メソッドをオーバーライドします。
public class AppNavigationController : UINavigationController
{
//...
public override UIViewController PopViewController(bool animated)
{
UIViewController topView = TopViewController;
if (topView != null)
{
// Dispose of ViewController on back navigation.
topView.Dispose();
}
return base.PopViewController(animated);
}
}
PopViewController
オーバーライドは、iOS ネイティブ ナビゲーション スタックからポップされた UIViewController
オブジェクトの Dispose
メソッドを呼び出します。 これを行わないと、UIViewController
およびアタッチされた Page
オブジェクトが孤立します。
重要
孤立したオブジェクトはガベージ コレクションが行われないため、メモリ リークが発生します。
Android
Android では、通常、MainActivity
クラスの OnCreate
オーバーライドは、アプリケーション起動関連のタスクを実行する場所です。 次のコード例は、サンプル アプリケーションの MainActivity
クラスを示しています。
public class MainActivity : AppCompatActivity
{
public static string FolderPath { get; private set; }
public static MainActivity Instance;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
Forms.Init(this, bundle);
// Create app-level resource dictionary.
Xamarin.Forms.Application.Current = new Xamarin.Forms.Application();
Xamarin.Forms.Application.Current.Resources = new MyDictionary();
Instance = this;
SetContentView(Resource.Layout.Main);
var toolbar = FindViewById<Toolbar>(Resource.Id.toolbar);
SetSupportActionBar(toolbar);
SupportActionBar.Title = "Notes";
FolderPath = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData));
NotesPage notesPage = new NotesPage()
{
// Set the parent so that the app-level resource dictionary can be located.
Parent = Xamarin.Forms.Application.Current
};
AndroidX.Fragment.App.Fragment notesPageFragment = notesPage.CreateSupportFragment(this);
SupportFragmentManager
.BeginTransaction()
.Replace(Resource.Id.fragment_frame_layout, mainPage)
.Commit();
//...
notesPage.Parent = null;
}
...
}
OnCreate
メソッドは、次のタスクを実行します。
- Xamarin.Forms は、メソッドを
Forms.Init
呼び出すと初期化されます。 - 新しい
Xamarin.Forms.Application
オブジェクトが作成され、そのアプリケーション レベルのリソース ディクショナリが XAML で定義されているResourceDictionary
に設定されます。 MainActivity
クラスへの参照は、static
Instance
フィールドに格納されます。 これは、他のクラスがMainActivity
クラスで定義されたメソッドを呼び出すためのメカニズムを提供するためです。Activity
コンテンツはレイアウト リソースから設定されます。 サンプル アプリケーションでは、レイアウトはToolbar
を含むLinearLayout
と、フラグメント コンテナーとして機能するFrameLayout
で構成されています。Toolbar
が取得され、Activity
の操作バーとして設定され、操作バーのタイトルが設定されます。FolderPath
プロパティは、メモ データが保存されるデバイス上のパスに初期化されます。NotesPage
オブジェクトが作成されます。これは XAML で定義された Xamarin.FormsContentPage
から派生したページであり、その親は以前に作成したXamarin.Forms.Application
オブジェクトに設定されています。NotesPage
オブジェクトは、CreateSupportFragment
拡張メソッドを使用してFragment
に変換されます。SupportFragmentManager
クラスは、FrameLayout
インスタンスをNotesPage
クラスのFragment
に置き換えるトランザクションを作成してコミットします。- メモリ リークを防ぐために、
NotesPage
オブジェクトのParent
プロパティはnull
に設定されます。
フラグメントの詳細については、「フラグメント」を参照してください。
OnCreate
メソッドが実行されると、次のスクリーンショットに示すように、Xamarin.FormsNotesPage
クラスで定義されている UI が表示されます。
重要
ContentPage
から派生したページはすべて、ページの Parent
プロパティが Application
オブジェクトに設定されている場合、アプリケーションレベルの ResourceDictionary
で定義されているリソースを使用できます。
NotesPage
分離コードで次のイベント ハンドラーが実行されます。
void OnNoteAddedClicked(object sender, EventArgs e)
{
MainActivity.Instance.NavigateToNoteEntryPage(new Note());
}
static
MainActivity.Instance
フィールドを使用すると、次のコード例に示すように、MainActivity.NavigateToNoteEntryPage
メソッドを呼び出すことができます。
public void NavigateToNoteEntryPage(Note note)
{
NoteEntryPage noteEntryPage = new NoteEntryPage
{
BindingContext = note,
// Set the parent so that the app-level resource dictionary can be located.
Parent = Xamarin.Forms.Application.Current
};
AndroidX.Fragment.App.Fragment noteEntryFragment = noteEntryPage.CreateSupportFragment(this);
SupportFragmentManager
.BeginTransaction()
.AddToBackStack(null)
.Replace(Resource.Id.fragment_frame_layout, noteEntryFragment)
.Commit();
noteEntryPage.Parent = null;
}
NavigateToNoteEntryPage
メソッドは、Xamarin.FormsContentPage
から派生したページを CreateSupportFragment
拡張メソッドを使用して Fragment
に変換し、フラグメント バック スタックに Fragment
を追加します。 そのため、次のスクリーンショットに示すように、Xamarin.FormsNoteEntryPage
で定義されている UI が表示されます。
NoteEntryPage
が表示されたときに、戻る矢印をタップすると、フラグメント バック スタックから NoteEntryPage
の Fragment
がポップされ、ユーザーは NotesPage
クラスの Fragment
に戻ります。
戻るナビゲーションのサポートを有効にする
SupportFragmentManager
クラスには、フラグメント バック スタックの内容が変更されるたびに発生する BackStackChanged
イベントがあります。 MainActivity
クラスの OnCreate
メソッドには、このイベントの匿名イベント ハンドラーが含まれています。
SupportFragmentManager.BackStackChanged += (sender, e) =>
{
bool hasBack = SupportFragmentManager.BackStackEntryCount > 0;
SupportActionBar.SetHomeButtonEnabled(hasBack);
SupportActionBar.SetDisplayHomeAsUpEnabled(hasBack);
SupportActionBar.Title = hasBack ? "Note Entry" : "Notes";
};
フラグメント バック スタックに 1 つ以上の Fragment
インスタンスがある場合、このイベント ハンドラーにより操作バーに [戻る] ボタンが表示されます。 [戻る] ボタンをタップした場合の応答は、OnOptionsItemSelected
オーバーライドによって処理されます。
public override bool OnOptionsItemSelected(Android.Views.IMenuItem item)
{
if (item.ItemId == global::Android.Resource.Id.Home && SupportFragmentManager.BackStackEntryCount > 0)
{
SupportFragmentManager.PopBackStack();
return true;
}
return base.OnOptionsItemSelected(item);
}
OnOptionsItemSelected
オーバーライドは、オプション メニューの項目が選択されるたびに呼び出されます。 この実装は、[戻る] ボタンが選択されており、フラグメント バック スタックに 1 つ以上の Fragment
インスタンスがある場合に、フラグメント バック スタックから現在のフラグメントをポップします。
複数のアクティビティ
アプリケーションが複数のアクティビティで構成されている場合、ContentPage
から派生したページを各アクティビティに埋め込むことができます。 このシナリオでは、Forms.Init
メソッドは、Xamarin.FormsContentPage
を埋め込む最初の Activity
の OnCreate
オーバーライドでのみ呼び出される必要があります。 ただし、これには次のような影響があります。
Xamarin.Forms.Color.Accent
の値は、Forms.Init
メソッドを呼び出したActivity
から取得されます。Xamarin.Forms.Application.Current
の値は、Forms.Init
メソッドを呼び出したActivity
に関連付けられます。
ファイルの選択
HTML の [ファイルの選択] ボタンをサポートする必要がある WebView
を使用する ContentPage
から派生したページを埋め込む場合、Activity
が OnActivityResult
メソッドをオーバーライドする必要があります。
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
ActivityResultCallbackRegistry.InvokeCallback(requestCode, resultCode, data);
}
UWP
UWP では、ネイティブ App
クラスは、通常、アプリケーション起動関連のタスクを実行する場所です。 Xamarin.Forms は、通常、Xamarin.Forms UWP アプリケーションではネイティブ App
クラスの OnLaunched
オーバーライドで初期化され、Forms.Init
メソッドに LaunchActivatedEventArgs
引数を渡します。 このため、Xamarin.FormsContentPage
から派生したページを使用するネイティブ UWP アプリケーションでは、App.OnLaunched
メソッドから Forms.Init
メソッドを最も簡単に呼び出すことができます。
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
// ...
Xamarin.Forms.Forms.Init(e);
// Create app-level resource dictionary.
Xamarin.Forms.Application.Current = new Xamarin.Forms.Application();
Xamarin.Forms.Application.Current.Resources = new MyDictionary();
// ...
}
さらに、OnLaunched
メソッドでは、アプリケーションで必要なアプリケーション レベルのリソース ディクショナリを作成することもできます。
既定では、ネイティブ App
クラスは、アプリケーションの最初のページとして MainPage
クラスを起動します。 次のコード例は、サンプル アプリケーションの MainPage
クラスを示しています。
public sealed partial class MainPage : Page
{
NotesPage notesPage;
NoteEntryPage noteEntryPage;
public static MainPage Instance;
public static string FolderPath { get; private set; }
public MainPage()
{
this.NavigationCacheMode = NavigationCacheMode.Enabled;
Instance = this;
FolderPath = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData));
notesPage = new Notes.UWP.Views.NotesPage
{
// Set the parent so that the app-level resource dictionary can be located.
Parent = Xamarin.Forms.Application.Current
};
this.Content = notesPage.CreateFrameworkElement();
// ...
notesPage.Parent = null;
}
// ...
}
MainPage
コンストラクターは、次のタスクを実行します。
- キャッシュはページに対して有効になっており、ユーザーがページに戻ったときに新しい
MainPage
が作成されません。 MainPage
クラスへの参照は、static
Instance
フィールドに格納されます。 これは、他のクラスがMainPage
クラスで定義されたメソッドを呼び出すためのメカニズムを提供するためです。FolderPath
プロパティは、メモ データが保存されるデバイス上のパスに初期化されます。NotesPage
オブジェクトが作成されます。これは XAML で定義された Xamarin.FormsContentPage
から派生したページであり、その親は以前に作成したXamarin.Forms.Application
オブジェクトに設定されています。NotesPage
オブジェクトは、CreateFrameworkElement
拡張メソッドを使用してFrameworkElement
に変換され、MainPage
クラスのコンテンツとして設定されます。- メモリ リークを防ぐために、
NotesPage
オブジェクトのParent
プロパティはnull
に設定されます。
MainPage
コンストラクターが実行されると、次のスクリーンショットに示すように、Xamarin.FormsNotesPage
クラスで定義されている UI が表示されます。
重要
ContentPage
から派生したページはすべて、ページの Parent
プロパティが Application
オブジェクトに設定されている場合、アプリケーションレベルの ResourceDictionary
で定義されているリソースを使用できます。
NotesPage
分離コードで次のイベント ハンドラーが実行されます。
void OnNoteAddedClicked(object sender, EventArgs e)
{
MainPage.Instance.NavigateToNoteEntryPage(new Note());
}
static
MainPage.Instance
フィールドを使用すると、次のコード例に示すように、MainPage.NavigateToNoteEntryPage
メソッドを呼び出すことができます。
public void NavigateToNoteEntryPage(Note note)
{
noteEntryPage = new Notes.UWP.Views.NoteEntryPage
{
BindingContext = note,
// Set the parent so that the app-level resource dictionary can be located.
Parent = Xamarin.Forms.Application.Current
};
this.Frame.Navigate(noteEntryPage);
noteEntryPage.Parent = null;
}
UWP でのナビゲーションは、通常、Page
引数を受け取る Frame.Navigate
メソッドを使用して実行されます。 Xamarin.Forms は、ContentPage
から派生したページ インスタンスを受け取る Frame.Navigate
拡張メソッドを定義します。 そのため、NavigateToNoteEntryPage
メソッドを実行すると、次のスクリーンショットに示すように、Xamarin.FormsNoteEntryPage
で定義されている UI が表示されます。
NoteEntryPage
が表示されたときに、戻る矢印をタップすると、アプリ内のバック スタックから NoteEntryPage
の FrameworkElement
がポップされ、ユーザーは NotesPage
クラスの FrameworkElement
に戻ります。
ページのサイズ変更のサポートを有効にする
UWP アプリケーション ウインドウのサイズを変更すると、Xamarin.Forms コンテンツのサイズも変更されます。 これを行うには、MainPage
コンストラクターで Loaded
イベントのイベント ハンドラーを登録します。
public MainPage()
{
// ...
this.Loaded += OnMainPageLoaded;
// ...
}
Loaded
イベントは、ページがレイアウトされ、レンダリングされ、やり取りする準備ができたときに発生し、それに応じて OnMainPageLoaded
メソッドを実行します。
void OnMainPageLoaded(object sender, RoutedEventArgs e)
{
this.Frame.SizeChanged += (o, args) =>
{
if (noteEntryPage != null)
noteEntryPage.Layout(new Xamarin.Forms.Rectangle(0, 0, args.NewSize.Width, args.NewSize.Height));
else
notesPage.Layout(new Xamarin.Forms.Rectangle(0, 0, args.NewSize.Width, args.NewSize.Height));
};
}
OnMainPageLoaded
メソッドは、 Frame.SizeChanged
イベントの匿名イベント ハンドラーを登録します。これは、ActualHeight
または ActualWidth
プロパティが Frame
で変更されたときに発生します。 それに応じて、アクティブ ページの Xamarin.Forms コンテンツは、Layout
メソッドを呼び出すとサイズが変更されます。
戻るナビゲーションのサポートを有効にする
UWP では、アプリケーションは、さまざまなデバイス フォーム ファクターにわたって、すべてのハードウェアとソフトウェアの [戻る] ボタンの戻るナビゲーションを有効にする必要があります。 これを実現するには、MainPage
コンストラクターで実行できる BackRequested
イベントのイベント ハンドラーを登録します。
public MainPage()
{
// ...
SystemNavigationManager.GetForCurrentView().BackRequested += OnBackRequested;
}
アプリケーションが起動されると、GetForCurrentView
メソッドは現在のビューに関連付けられている SystemNavigationManager
オブジェクトを取得し、BackRequested
イベントのイベント ハンドラーを登録します。 アプリケーションはフォアグラウンド アプリケーションの場合にのみこのイベントを受け取り、それに応じて OnBackRequested
イベント ハンドラーを呼び出します。
void OnBackRequested(object sender, BackRequestedEventArgs e)
{
Frame rootFrame = Window.Current.Content as Frame;
if (rootFrame.CanGoBack)
{
e.Handled = true;
rootFrame.GoBack();
noteEntryPage = null;
}
}
OnBackRequested
イベント ハンドラーは、アプリケーションのルート フレームで GoBack
メソッドを呼び出し、イベントを処理済みとしてマークするように BackRequestedEventArgs.Handled
プロパティを true
に設定します。 イベントを処理済みとしてマークしないと、イベントが無視される可能性があります。
アプリケーションにより、タイトル バーに [戻る] ボタンを表示するかどうかが選択されます。 これを行うには、App
クラスで、AppViewBackButtonVisibility
プロパティを AppViewBackButtonVisibility
列挙値のいずれかに設定します。
void OnNavigated(object sender, NavigationEventArgs e)
{
SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility =
((Frame)sender).CanGoBack ? AppViewBackButtonVisibility.Visible : AppViewBackButtonVisibility.Collapsed;
}
OnNavigated
イベント ハンドラーは、 Navigated
イベントの発生に応じて実行され、ページ ナビゲーションが発生したときにタイトル バーの [戻る] ボタンの可視性を更新します。 これにより、アプリ内のバック スタックが空ではない場合はタイトル バーの [戻る] ボタンが表示され、アプリ内のバック スタックが空の場合はタイトル バーから削除されます。
UWP での戻るナビゲーションのサポートの詳細については、UWP アプリのナビゲーション履歴と戻るナビゲーションに関するページを参照してください。