[VS-Mac]VisualStudio for Mac (Cocoa)でファイルダイアログ表示


 VisualStudio for Macをインストールしたものの、Cocoa GUアプリ作成にはXcodeとInterfaceBuilder及びAPIの知識が必要で、自分のようにWindowsから移行してXcodeとSwiftのGUアプリに挫折した者にとっては使いこなせない強敵です。
 幸いに、XamarinのMacに関するGuidesのページでサンプルアプリのチュートリアルと説明の記事があり、慣れないAPIと英語ではあるものの、なんとか自分でもできそうな気がしてしまいます。
 ところが、自分で新たなツールを作ろうとすると十分に理解できていないことから、何度も同じことを調べ直さなければならず大変でした。

 そこで、小物ツール作成時に役立つように、これらの記事とサンプルコードを元に、個人的に利用する可能性が高い機能を私的Tutorialとして記事にしておくことにします。

 第1回目は、InterfaceBuilderの使い方とコード実装を、ツールバーとファイルダイアログの表示を例にした備忘録です。

利用するAPI:

概要

  • ツールボタンのクリックでファイルを開くダイアログを表示。
  • Openで選択したファイル名をViewに配置したラベルに表示する。
  • ツールバーのParentであるWindowsControllerからViewControllerのViewに存在するコントロールを操作する例。
  • おまけとして、アプリを直接終了できるツールボタン。

ソリューションの新規作成

  • VisualStudioで「NewProject」
  • 「Mac」「Cocoa App」を選択
  • AppName 「MyTutorial_OpenFile」
  • 作成

InterfaceBuilderでの操作

Main.storyboardをダブルクリックして、Xcodeを起動

WindowsControllerのクラス名を設定

  1. ツールボタンのアクションを追加するためのWindowsController.hをXcodeで表示させるために必要。
  2. Window Controller を選択、Identify Inspectorを表示してClassを「WindowController」と入力。
  3. XcodeメニューからSaveして、VisualStudioに戻る。
  4. VisualStudioに「WindowController.cs」が追加された。
  5. Main.storyboardをダブルクリックして、Xcodeを再度表示してコードに「WindowController.h」が追加されていることを確認。
  • VisualStudioに戻る時に、Xcodeとの同期エラーのダイアログが出現することがまれにあるが、特に支障はないようだ。

コントロールの追加

  1. WindowsControllerにToolbarを追加し、これをクリックしてツールバーの編集モードにする。
  2. OpenFile用のImageToolbarItemを追加して、ImageName(アイコン)とLabelを「File」に変更。
  3. 同様にQuit用ImageToolbarItemを追加して、Labelを「Quit」に変更。
  4. AllowedToolbarItemsに追加したItemを、DefaultToolbarItemsにドラッグ。不要のツールバーをツールバー外にドロップして削除。

ツールボタンActionの追加

  1. XcodeでAssistantEditorを表示(右上のダブルサークル)
  2. AssistantEditorに「WindowController.cs」を表示

  3. ツールバーのAllowedToolbarItemから「File」Itemを選択して、Ctrlキーを押したまま「WindowController.h」の @end の前にドラッグ

  4. Connectionを「Actionに変更」。Nameに「FileButton_Click」と入力して「connect」ボタンをクリック。

  5. 同様に「Quit」ItemもActionとしてドラッグし、Nameを「QuitButton_Click」と入力。

  6. ツールバーの「done」ボタンをクリックして編集モードから抜ける。

  7. Save後のWindowController.designer.csにActionの関数宣言が追加されている。

ViewControllerにラベルを追加

  1. ViewControllerを表示
  2. LabelをViewにドラッグしてサイズを適当に変更
  3. AssistantEditorにViewController.hを表示
  4. 追加したLabelを選択肢、Ctrlキーを押したまま @end の前にドラッグ
  5. Connectionは「Outlet」のままで変更せず、Nameを「Label1」と入力してConnect。

  6. XcodeをSaveしてVisualStudioに戻る。

  7. ViewController.designer.csにLabel1がNSTextFieldの変数として宣言されている。

VisualStudioでコードの追加と編集

ViewController.csの編集

  1. Windowタイトルとラベルの表示テキストを変更する関数の追加
    //chnage title  UserInterface - Windows - Setting a Window's Title
    public override void ViewWillAppear()
    {
          base.ViewWillAppear();
          this.View.Window.Title = "My Tutorial NSOpenPanel";
          ChangeLabeltext("");
    }
    public void ChangeLabeltext(string str)
    {
          this.Label1.StringValue = str;
    }

WindowController.csの編集

  1. ViewControllerを参照するController変数を作成
    public ViewController Controller
    {
        get { return ContentViewController as ViewController; }
    }

 
2. FileButton_Click アクションプロシージャー

    partial void FileButton_Click(NSObject sender)
    {
              var dlg = NSOpenPanel.OpenPanel;
              dlg.CanChooseFiles = true;
              dlg.CanChooseDirectories = false;
              dlg.AllowsMultipleSelection = false;
              dlg.DirectoryUrl = NSUrl.FromString(Environment.SpecialFolder.MyPictures.ToString());
              dlg.AllowedFileTypes = new string[] { "png", "jpeg", "jpg" };

            if ( dlg.RunModal() == 1)
              {
                    if (dlg.Urls[0] != null)
                    {
                        Controller.ChangeLabeltext(dlg.Urls[0].Path);
                    }
              }
            else
            {
                  var alert = new NSAlert()
                  {
                        AlertStyle = NSAlertStyle.Informational,
                        InformativeText = "Cancel Button Clicked",
                        MessageText = "Alert",
                  };
                  alert.RunModal();
            }
    }
  1. QuitButton_Click アクションプロシージャー
        partial void QuitButton_Click(NSObject sender)
        {
                  NSApplication.SharedApplication.Terminate(Self);
        }

コード全体像

ViewController.cs

using System;

using AppKit;
using Foundation;

namespace MyTutorial_OpenFile
{
    public partial class ViewController : NSViewController
    {
        public ViewController(IntPtr handle) : base(handle)
        {
        }

        public override void ViewDidLoad()
        {
            base.ViewDidLoad();

            // Do any additional setup after loading the view.
        }

        //###### Quote from Xamarin page ##########
        //https://developer.xamarin.com/guides/mac/user-interface/working-with-windows/
        //chnage title  UserInterface - Windows - Setting a Window's Title
        public override void ViewWillAppear()
        {
            base.ViewWillAppear();
            this.View.Window.Title = "My Tutorial NSOpenPanel";
            ChangeLabeltext("");
        }
        //#########################################
        public void ChangeLabeltext(string str)
        {
            this.Label1.StringValue = str;
        }

        public override NSObject RepresentedObject
        {
            get
            {
                return base.RepresentedObject;
            }
            set
            {
                base.RepresentedObject = value;
                // Update the view, if already loaded.
            }
        }
    }
}

WindowController.cs

// This file has been autogenerated from a class added in the UI designer.
using System;
using Foundation;
using AppKit;
namespace MyTutorial_OpenFile
{
    public partial class WindowController : NSWindowController
    {
        //###### Quote from Xamarin page ##########
        //https://developer.xamarin.com/guides/mac/application_fundamentals/copy-paste/
        public ViewController Controller
        {
            get { return ContentViewController as ViewController; }
        }
        public WindowController(IntPtr handle) : base(handle)
        {
        }
        #region ToolButton Action
        partial void FileButton_Click(NSObject sender)
        {
            //###### Quote from Xamarin page ##########
            //https://developer.xamarin.com/guides/mac/user-interface/working-with-dialogs/#The_Open_Dialog
            var dlg = NSOpenPanel.OpenPanel;
            dlg.CanChooseFiles = true;
            dlg.CanChooseDirectories = false;
            dlg.AllowsMultipleSelection = false;
            dlg.DirectoryUrl = NSUrl.FromString(Environment.SpecialFolder.MyPictures.ToString());
            dlg.AllowedFileTypes = new string[] { "png", "jpeg", "jpg" };

            if ( dlg.RunModal() == 1)
            {
                if (dlg.Urls[0] != null)
                {
                    Controller.ChangeLabeltext(dlg.Urls[0].Path);
                }
            }
            else
            {
                //###### Quote from Xamarin page ##########
                //https://developer.xamarin.com/guides/mac/user-interface/working-with-alerts/
                var alert = new NSAlert()
                {
                    AlertStyle = NSAlertStyle.Informational,
                    InformativeText = "Cancel Button Clicked",
                    MessageText = "Alert",
                };
                alert.RunModal();
            }
        }
        partial void QuitButton_Click(NSObject sender)
        {
            //######## Refer to StackOverFlow ##########
            //http://stackoverflow.com/questions/1748895/how-to-properly-quit-application-call-exit0
            NSApplication.SharedApplication.Terminate(Self);
        }
        #endregion
    }
}

Reference:

  1. Monoのライセンス Mono Licensing
  2. Xamarine - Developers - Guides - Mac - Getting Started - Hello,Mac
  3. Xamarine - Developers - Guides - Mac - Application Fundamentals - Working with .xib Files   
  4. Xamarine - Developers - Guides - Mac - Application Fundamentals - Working with Copy and Paste WindowControllerからViewContorollerの操作(ContentViewController)
  5. Xamarine - Developers - Guides - Mac - User Interface - Toolbars
  6. Xamarine - Developers - Guides - Mac - User Interface - Dialogs
      file dialogの引用修正
  7. Xamarine - Developers - Guides - Mac - User Interface - [Windows]  (https://developer.xamarin.com/guides/mac/user-interface/working-with-windows/)   Window Title変更の引用修正
  8. Xamarine - Developers - Guides - Mac - User Interface - Alerts
  9. viva Cocoa Windowsなどのほかのプラットフォームから転向されてきた方へ
  10. stackoverflow How to properly quit application, call exit(0)?
      Swiftのコードを参考にした。

2-8で引用した部分の著作権はXamarinに帰属します。

License:

Copyright (c) 2017 grayhead0603
Released under the MIT license