Help us understand the problem. What is going on with this article?

Xamarin.Macにおけるシートいろいろ(ファイルダイアログ編)

More than 5 years have passed since last update.

Problem

ファイルダイアログもシートで出せます。
シートで出すことにより,どのアプリケーションのダイアログかが明確になるので,できれば使っていきたいところです。
シートを乱発するとどうなるか,そしてこれを防ぐ方法についても本稿でご紹介します。

Prerequisite

Xamarin.Mac プロジェクトを作成し,MainWindow.xibをXCodeで開いて,このような感じにしてあります。
XCode上のUIデザイン

NSOpenPanel

いわゆるオープンファイルダイアログです。
オプションを指定することでフォルダ選択ダイアログに仕立てることも可能です。

MainWindowController.cs
public override void WindowDidLoad()
{
    base.WindowDidLoad();

    OpenButton.Activated += (sender, _) => ShowOpenPanel((NSObject)sender);
}

[Export("openDocument:")]
void ShowOpenPanel(NSObject sender)
{
    using(var panel = new NSOpenPanel()){
        // 複数選択の可否
        panel.AllowsMultipleSelection = false;
        // ファイル選択の可否
        panel.CanChooseFiles = true;
        // ディレクトリ選択の可否
        panel.CanChooseDirectories = true;
        // 受け入れるファイルタイプ
        // 拡張子のみ,ピリオドなし,複数指定可能
        panel.AllowedFileTypes = new[]{ "txt" };
        // 開くボタンのテキスト,指定しない場合はOS標準
        panel.Prompt = "開く";
        // モーダルウィンドウのタイトル
        panel.Title = "ウィンドウタイトル";

        // モーダル表示
        var ret = panel.RunModal();

        // キャンセルが押された場合 0 が返る
        if (ret > 0)
            PathField.StringValue = panel.Url.Path;
    }
}

モーダルとして表示

先頭の[Export]によりセレクタを宣言することで,メニューバーの「開く」に関連付けています。
RunModal しているのでモーダルダイアログとして表示されます。
これをシートにする場合は以下のようになります。

MainWindowController.cs
[Export("openDocument:")]
void ShowOpenPanel(NSObject sender)
{
    var panel = new NSOpenPanel{ CanChooseFiles = true, AllowedFileTypes = new[]{ "cs" }, ReleasedWhenClosed = true };

    panel.BeginSheet(Window, ret =>
        {
            panel.EndSheet(Window);
            if (ret > 0)
                PathField.StringValue = panel.Url.Path;
        });
}

BeginSheetEndSheetは対応させなくてはなりません。また,using句でくくると破棄タイミングがよろしくないので,代わりにReleasedWhenClosedtrueにしておきます。
ShowAsSheet

NSSavePanel

保存先の選択に使います。NSOpenPanelはこれを継承しています。こちらはシートで表示する場合だけ。

MainWindowController.cs
[Export("saveDocumentAs:")]
void ShowSavePanel(NSObject sender)
{
    var panel = new NSSavePanel();
    // 許容する拡張子
    panel.AllowedFileTypes = new[]{ "cs" };
    // フォルダの作成ボタンを表示
    panel.CanCreateDirectories = true;
    panel.ReleasedWhenClosed = true;
    panel.Message = "SavePanelを通して伝えたいこと";

    panel.BeginSheet(Window, ret =>
        {
            panel.EndSheet(Window);
            if (ret > 0)
                PathField.StringValue = panel.Url.Path;
        });
}

NSSavePanel

必要であればAccessoryViewで何でも追加可能。

MainWindowController.cs
var img = new NSImageView(new System.Drawing.RectangleF(0, 0, 64, 64))
    { Image = NSImage.ImageNamed(NSImageName.QuickLookTemplate), ImageScaling = NSImageScale.ProportionallyUpOrDown };
panel.AccessoryView = img;

accview

Conclusion

Xamarin.Macにおけるシートいろいろはこれで完結です。
本当はシート乱発時の危険な動作についてまとめたいですが,10.9以降のAPIを使う場合は起きないようなので,大丈夫だと信じて割愛します。
ここまでのシートいろいろまとめはUnified APIでもほぼ同じコードで動作します。

ailen0ada
Xamarin.Mac の人です。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away