Xamarin.Macにおけるシートいろいろ(NSAlert編)

##Problem
OSXのユーザーインタフェースガイドライン的にモーダルダイアログはよろしくないらしいので，できるだけシートを使っていくことになります。
シートを出すにもその目的や，やりたいことに応じていろいろあります。本稿では`NSAlert`に着目し，次稿では`NSWindow`に着目します。

##with NSAlert
###Notify
お手軽。Windowsで言うところのMessageBoxに相当します。
表示は簡単。使いたい場所で以下のように書きます。

```csharp:simpleAlert
using (var alert = new NSAlert())
{
    alert.AlertStyle = NSAlertStyle.Informational;
    alert.MessageText = "タイトル";
    alert.InformativeText = "メッセージ";
    alert.RunSheetModal([NSWindow]);
}
```
`[NSWindow]`には紐付けるウィンドウを指定します。`null`にすると通常のダイアログ表示になります。
![Screen Shot 2014-08-20 at 13.06.05.png](https://qiita-image-store.s3.amazonaws.com/0/34563/f5ac4f26-c11b-05e5-d971-407d5162f0c8.png "NSAlert as sheet")
![Screen Shot 2014-08-20 at 13.07.39.png](https://qiita-image-store.s3.amazonaws.com/0/34563/220a7f86-4d4e-6c00-7e0c-689308f079b0.png "NSAlert as dialog")

###Confirm
ボタンを表示して結果を受け取る方法。

```csharp:simpleQuestion
using (var alert = new NSAlert())
{
    alert.AlertStyle = NSAlertStyle.Informational;
    alert.MessageText = "タイトル";
    alert.InformativeText = "聞きたいこと";
    alert.AddButton("はい");
    alert.AddButton("いいえ");
    var ret = alert.RunSheetModal([NSWindow]);
    return (ret == (int)NSAlertButtonReturn.First);
}
```
![Screen Shot 2014-08-20 at 13.09.08.png](https://qiita-image-store.s3.amazonaws.com/0/34563/f1876da8-f06e-4eac-e286-1193a4a381c3.png "NSAlert with two buttons")

1アラートには3つまでボタンを設けることができ，どれが押されたかは`NSAlertButtonReturn`列挙で取得できます（First, Second, Third）。`AddButton`すると`NSAlert`の`Buttons[]`に追加されるので，この順番になります。
*追記(201408201515)* 嘘です。結構好きな数追加できました。Thid以降は1004,1005...と返却される`int`がインクリメントされていきます。

###Suppress
あとよくあるのは，「二度と表示してくれるな」チェックボックスです。こんな感じです。

```csharp:suppression
using (var alert = new NSAlert())
{
    alert.AlertStyle = NSAlertStyle.Informational;
    alert.MessageText = "お節介";
    alert.InformativeText = "お節介なメッセージ";
    alert.AddButton("はい");
    alert.AddButton("いいえ");
    alert.AddButton("キャンセル");
    alert.ShowsSuppressionButton = true;
    var ret = alert.RunSheetModal(Window);
    Debug.WriteLine(ret == (int)NSAlertButtonReturn.Third);
    Debug.WriteLine(alert.SuppressionButton.State);
}
```
表示終了後に，`SuppressionButton`の`State (On/Off)`で判定できます。
![Screen Shot 2014-08-20 at 13.18.57.png](https://qiita-image-store.s3.amazonaws.com/0/34563/7315cf7b-db7b-2f80-af76-cf7824e98982.png "NSAlert suppression")
表示が英語なのはOSの言語設定の依るもので，これもただの`NSButton`なので，変更できます。上のコードで表示前に`alert.SuppressionButton.Title = "もういいよそういうのは";`を追加するとこんな感じに。
![Screen Shot 2014-08-20 at 13.43.48.png](https://qiita-image-store.s3.amazonaws.com/0/34563/3d369c49-b5a8-d528-b887-92fd0e0c860e.png "suppress2")


###Prompt
VBAとかでよくある，一行入力させるメッセージボックス的な。それを実現する方法。

```csharp:prompt
var name = "default";
using (var alert = new NSAlert())
{
    alert.AlertStyle = NSAlertStyle.Informational;
    alert.MessageText = "おしえてくん";
    alert.InformativeText = "おなまえはなにかな？";
    alert.AddButton("確定");
    alert.AddButton("取消");

    var nameBox = new NSTextField(new RectangleF(0, 0, 200, 24));
    alert.AccessoryView = nameBox;

    var ret = alert.RunSheetModal(Window);
    Debug.WriteLine(ret == (int)NSAlertButtonReturn.First);
    name = nameBox.StringValue;
}
Debug.WriteLine(name);
```
![Screen Shot 2014-08-20 at 13.28.31.png](https://qiita-image-store.s3.amazonaws.com/0/34563/aca561a9-ea58-e38e-0cd7-616278ec0874.png "NSAlertprompt")

`NSAlert.AccessoryView`は`NSView`なので，入れようと思えば何でも入りますが，そこまでするなら`NSWindow`をシート化したほうがいいです。アラートなので，ボタンを消すことはできませんし。

##Conclusion
これでNSAlertはバッチリ。結果取得は`BeginSheetForResponce`を呼び出すことで非同期にできます。