この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
1 はじめに
CX事業本部の平内(SIN)です。
Xamarin.Macを使用すると、C#でネイティブなMacのアプリが作成可能です。 ここでは、私自身がXamarin.Macに入門して学習した事項を覚書として書かせて頂いています。
今回は、フォルダを指定して、その中にある画像ファイルを一覧表示してみました。
2 画面構成
Interface Builderでの画面設計です。
最初に、ウインドウいっぱいに上下分割のSplit Viewを置きました。そして、上側のビューの高さを固定し、ImageButtonを配置しました。
Outletは、ImageButton(NSButton)とCollectionView(NSCollectionView)という名前で作成しています。
3 NSCollectionViewItem
ファイル > 新しいファイル > Mac > View Controllerと辿り、新規にビューを作成します。(ここでは、名前をPictureViewとしました)
この時、以下の3つのファイルが生成されますが、PictureView.xibは、PictureViewController.xibにRenameしています。
- PictureView.cs
- PictureView.xib
- PictureViewController.cs
Interface Builderで、LabelとImageViewを配置しました。
Image Viewは、Owner(PictureViewController.cs)のImageプロパティにバインディングしています。
Labelは、OwnerのNameプロパティにバインディングしています。
PictureViewController.csは、継承元をNSCollectionViewItemに変更し、バインディング用に2つのプロパティを公開しています。
PictureViewController.cs
public partial class PictureViewController : NSCollectionViewItem {
NSImage _image;
string _name;
[Export("Image")]
public NSImage Image {
get {
return _image;
}
set {
WillChangeValue("Image");
_image = value;
DidChangeValue("Image");
}
}
[Export("Name")]
public string Name {
get { return _name; }
set {
WillChangeValue("Name");
_name = value;
DidChangeValue("Name");
}
}
// ・・・略・・・
}
4 Delegate/DataSource
デリゲートは、NSCollectionViewDelegateFlowLayoutを継承して作成しています。
public class CollectionViewDelegate: NSCollectionViewDelegateFlowLayout {
public CollectionViewDelegate() {
}
}
}
データソースは、NSCollectionViewDataSourceを継承して作成し、データとして、ファイルパスの一覧を保持させます。
データには、画像ファイルのパスが入っているので、GetItem()の段階で、NSImageを生成して、PictureViewControllerのプロパティを更新しています。
public class CollectionViewDataSource : NSCollectionViewDataSource {
// ファイル(パス)の一覧
public List<string> Files = new List<String>();
public CollectionViewDataSource() {}
public override NSCollectionViewItem GetItem(NSCollectionView collectionView, NSIndexPath indexPath) {
var item = collectionView.MakeItem("cell", indexPath) as PictureViewController;
var file = Files[(int)indexPath.Item];
// ファイル名
item.Name = Path.GetFileName(file);
// 画像
item.Image = new NSImage(file);
return item;
}
public override nint GetNumberofItems(NSCollectionView collectionView, nint section) {
return Files.Count;
}
}
5 ViewController
ViewController の ViewDidLoad() で、作成したデータソースとデリゲートをCollection Viewにセットしています。
また、ボタンをクリックされた際には、ディレクトリ選択のダイアログを表示し、選択された場合は、その中のファイル(jpg)一覧で、データソースを初期化します。
ViewController.cs
public partial class ViewController : NSViewController {
public ViewController(IntPtr handle) : base(handle) {
}
public override void ViewDidLoad() {
base.ViewDidLoad();
// Openボタンがクリックれた時のイベントを定義
ImageButton.Activated += ImageButton_Activated;
// PictureViewControllerの登録
CollectionView.RegisterClassForItem(typeof(PictureViewController), "cell");
// DataSource
CollectionView.DataSource = new CollectionViewDataSource();
// Flow layout
var flowLayout = new NSCollectionViewFlowLayout() {
ItemSize = new CGSize(150, 150),
SectionInset = new NSEdgeInsets(10, 10, 10, 20),
MinimumInteritemSpacing = 10,
MinimumLineSpacing = 10
};
CollectionView.WantsLayer = true;
CollectionView.CollectionViewLayout = flowLayout;
// Delegate
CollectionView.Delegate = new CollectionViewDelegate();
}
// Openクリック時の処理
private void ImageButton_Activated(object sender, EventArgs e) {
// ディレクトリ選択
var dlg = NSOpenPanel.OpenPanel;
dlg.CanChooseDirectories = true;
if(dlg.RunModal() == 1) {
var url = dlg.Urls[0];
if(url != null) {
// 選択されたディレクトリ内のjpgの一覧を取得
string[] files = Directory.GetFiles(url.Path, "*.jpg");
// Collection Viewのデータソースを更新する
((CollectionViewDataSource)CollectionView.DataSource).Files = files.ToList();
}
}
CollectionView.ReloadData();
}
// ・・・略・・・
}
6 最後に
今回は、フォルダを指定して画像ファイルを一覧してみました。データバインディングのコツが掴めれば、比較的にスムーズに実装が進みそうな気がしてます。
個人的には、ImageViewのバインディングタブでは、Dataが一番上になっているので、間違ってこちらでBind toしないように注意が必要かなと思いました。