Xamarin.Mac 中的來源清單
本文涵蓋在 Xamarin.Mac 應用程式中使用來源清單。 它描述如何在 Xcode 和 Interface Builder 中建立和維護來源清單,並在 C# 程式代碼中與其互動。
在 Xamarin.Mac 應用程式中使用 C# 和 .NET 時,您可以存取開發人員在 和 Xcode 中Objective-C運作的相同來源清單。 由於 Xamarin.Mac 直接與 Xcode 整合,因此您可以使用 Xcode 的 介面產生器 來建立和維護來源清單(或選擇性地直接在 C# 程式代碼中建立它們)。
[來源清單] 是一種特殊的大綱檢視類型,用來顯示動作的來源,例如 Finder 或 iTunes 中的側邊列。
在本文中,我們將討論在 Xamarin.Mac 應用程式中使用來源清單的基本概念。 強烈建議您先完成 Hello,Mac 文章,特別是 Xcode 和 Interface Builder 和 Outlets 和 Actions 簡介小節,因為它涵蓋我們將在本文中使用的重要概念和技術。
您可能也想要查看 Xamarin.Mac Internals 檔的公開 C# 類別/方法Objective-C一節,它也會說明 Register
用來將 C# 類別連接至Objective-C物件和 UI 元素的 和 Export
命令。
來源清單簡介
如上所述,[來源清單] 是特殊類型的大綱檢視,用來顯示動作的來源,例如 Finder 或 iTunes 中的側邊列。 [來源清單] 是一種數據表類型,可讓用戶展開或折疊階層式數據的數據列。 不同於數據表檢視,來源清單中的專案不在一般清單中,它們會組織在階層中,例如硬碟上的檔案和資料夾。 如果 [來源清單] 中的專案包含其他專案,使用者就可以展開或折迭該專案。
[來源清單] 是特別樣式的大綱檢視 (NSOutlineView
),本身是數據表檢視 (NSTableView
) 的子類別,因此會繼承其父類別的大部分行為。 因此,[大綱檢視] 也支援許多作業。來源清單也支援。 Xamarin.Mac 應用程式可控制這些功能,並可設定來源清單的參數(在程式代碼或介面產生器中),以允許或不允許某些作業。
來源清單不會儲存自己的數據,而是依賴數據源 (NSOutlineViewDataSource
) 視需要提供所需的數據列和數據行。
您可以藉由提供大綱檢視委派的子類別來NSOutlineViewDelegate
自定義來源清單的行為,以支援大綱類型來選取功能、項目選取和編輯、自定義追蹤,以及個別專案的自定義檢視。
由於來源清單會與數據表檢視和大綱檢視共用大部分的行為和功能,因此建議您先瀏覽我們的數據表檢視和大綱檢視檔,再繼續進行本文。
使用來源清單
[來源清單] 是一種特殊的大綱檢視類型,用來顯示動作的來源,例如 Finder 或 iTunes 中的側邊列。 不同於大綱檢視,在介面產生器中定義來源清單之前,讓我們在 Xamarin.Mac 中建立支持類別。
首先,讓我們建立新的 SourceListItem
類別來保存來源清單的數據。 在 方案總管 中,以滑鼠右鍵按兩下 [專案],然後選取 [新增>檔案...選取 [一般>空白類別],輸入 SourceListItem
[名稱],然後按下 [新增] 按鈕:
SourceListItem.cs
讓檔案看起來如下所示:
using System;
using System.Collections;
using System.Collections.Generic;
using AppKit;
using Foundation;
namespace MacOutlines
{
public class SourceListItem: NSObject, IEnumerator, IEnumerable
{
#region Private Properties
private string _title;
private NSImage _icon;
private string _tag;
private List<SourceListItem> _items = new List<SourceListItem> ();
#endregion
#region Computed Properties
public string Title {
get { return _title; }
set { _title = value; }
}
public NSImage Icon {
get { return _icon; }
set { _icon = value; }
}
public string Tag {
get { return _tag; }
set { _tag=value; }
}
#endregion
#region Indexer
public SourceListItem this[int index]
{
get
{
return _items[index];
}
set
{
_items[index] = value;
}
}
public int Count {
get { return _items.Count; }
}
public bool HasChildren {
get { return (Count > 0); }
}
#endregion
#region Enumerable Routines
private int _position = -1;
public IEnumerator GetEnumerator()
{
_position = -1;
return (IEnumerator)this;
}
public bool MoveNext()
{
_position++;
return (_position < _items.Count);
}
public void Reset()
{_position = -1;}
public object Current
{
get
{
try
{
return _items[_position];
}
catch (IndexOutOfRangeException)
{
throw new InvalidOperationException();
}
}
}
#endregion
#region Constructors
public SourceListItem ()
{
}
public SourceListItem (string title)
{
// Initialize
this._title = title;
}
public SourceListItem (string title, string icon)
{
// Initialize
this._title = title;
this._icon = NSImage.ImageNamed (icon);
}
public SourceListItem (string title, string icon, ClickedDelegate clicked)
{
// Initialize
this._title = title;
this._icon = NSImage.ImageNamed (icon);
this.Clicked = clicked;
}
public SourceListItem (string title, NSImage icon)
{
// Initialize
this._title = title;
this._icon = icon;
}
public SourceListItem (string title, NSImage icon, ClickedDelegate clicked)
{
// Initialize
this._title = title;
this._icon = icon;
this.Clicked = clicked;
}
public SourceListItem (string title, NSImage icon, string tag)
{
// Initialize
this._title = title;
this._icon = icon;
this._tag = tag;
}
public SourceListItem (string title, NSImage icon, string tag, ClickedDelegate clicked)
{
// Initialize
this._title = title;
this._icon = icon;
this._tag = tag;
this.Clicked = clicked;
}
#endregion
#region Public Methods
public void AddItem(SourceListItem item) {
_items.Add (item);
}
public void AddItem(string title) {
_items.Add (new SourceListItem (title));
}
public void AddItem(string title, string icon) {
_items.Add (new SourceListItem (title, icon));
}
public void AddItem(string title, string icon, ClickedDelegate clicked) {
_items.Add (new SourceListItem (title, icon, clicked));
}
public void AddItem(string title, NSImage icon) {
_items.Add (new SourceListItem (title, icon));
}
public void AddItem(string title, NSImage icon, ClickedDelegate clicked) {
_items.Add (new SourceListItem (title, icon, clicked));
}
public void AddItem(string title, NSImage icon, string tag) {
_items.Add (new SourceListItem (title, icon, tag));
}
public void AddItem(string title, NSImage icon, string tag, ClickedDelegate clicked) {
_items.Add (new SourceListItem (title, icon, tag, clicked));
}
public void Insert(int n, SourceListItem item) {
_items.Insert (n, item);
}
public void RemoveItem(SourceListItem item) {
_items.Remove (item);
}
public void RemoveItem(int n) {
_items.RemoveAt (n);
}
public void Clear() {
_items.Clear ();
}
#endregion
#region Events
public delegate void ClickedDelegate();
public event ClickedDelegate Clicked;
internal void RaiseClickedEvent() {
// Inform caller
if (this.Clicked != null)
this.Clicked ();
}
#endregion
}
}
在 方案總管 中,以滑鼠右鍵按兩下 [專案],然後選取 [新增>檔案...選取 [一般>空白類別],輸入 SourceListDataSource
[名稱],然後按兩下 [新增] 按鈕。 SourceListDataSource.cs
讓檔案看起來如下所示:
using System;
using System.Collections;
using System.Collections.Generic;
using AppKit;
using Foundation;
namespace MacOutlines
{
public class SourceListDataSource : NSOutlineViewDataSource
{
#region Private Variables
private SourceListView _controller;
#endregion
#region Public Variables
public List<SourceListItem> Items = new List<SourceListItem>();
#endregion
#region Constructors
public SourceListDataSource (SourceListView controller)
{
// Initialize
this._controller = controller;
}
#endregion
#region Override Properties
public override nint GetChildrenCount (NSOutlineView outlineView, Foundation.NSObject item)
{
if (item == null) {
return Items.Count;
} else {
return ((SourceListItem)item).Count;
}
}
public override bool ItemExpandable (NSOutlineView outlineView, Foundation.NSObject item)
{
return ((SourceListItem)item).HasChildren;
}
public override NSObject GetChild (NSOutlineView outlineView, nint childIndex, Foundation.NSObject item)
{
if (item == null) {
return Items [(int)childIndex];
} else {
return ((SourceListItem)item) [(int)childIndex];
}
}
public override NSObject GetObjectValue (NSOutlineView outlineView, NSTableColumn tableColumn, NSObject item)
{
return new NSString (((SourceListItem)item).Title);
}
#endregion
#region Internal Methods
internal SourceListItem ItemForRow(int row) {
int index = 0;
// Look at each group
foreach (SourceListItem item in Items) {
// Is the row inside this group?
if (row >= index && row <= (index + item.Count)) {
return item [row - index - 1];
}
// Move index
index += item.Count + 1;
}
// Not found
return null;
}
#endregion
}
}
這會提供來源清單的數據。
在 方案總管 中,以滑鼠右鍵按兩下 [專案],然後選取 [新增>檔案...選取 [一般>空白類別],輸入 SourceListDelegate
[名稱],然後按兩下 [新增] 按鈕。 SourceListDelegate.cs
讓檔案看起來如下所示:
using System;
using AppKit;
using Foundation;
namespace MacOutlines
{
public class SourceListDelegate : NSOutlineViewDelegate
{
#region Private variables
private SourceListView _controller;
#endregion
#region Constructors
public SourceListDelegate (SourceListView controller)
{
// Initialize
this._controller = controller;
}
#endregion
#region Override Methods
public override bool ShouldEditTableColumn (NSOutlineView outlineView, NSTableColumn tableColumn, Foundation.NSObject item)
{
return false;
}
public override NSCell GetCell (NSOutlineView outlineView, NSTableColumn tableColumn, Foundation.NSObject item)
{
nint row = outlineView.RowForItem (item);
return tableColumn.DataCellForRow (row);
}
public override bool IsGroupItem (NSOutlineView outlineView, Foundation.NSObject item)
{
return ((SourceListItem)item).HasChildren;
}
public override NSView GetView (NSOutlineView outlineView, NSTableColumn tableColumn, NSObject item)
{
NSTableCellView view = null;
// Is this a group item?
if (((SourceListItem)item).HasChildren) {
view = (NSTableCellView)outlineView.MakeView ("HeaderCell", this);
} else {
view = (NSTableCellView)outlineView.MakeView ("DataCell", this);
view.ImageView.Image = ((SourceListItem)item).Icon;
}
// Initialize view
view.TextField.StringValue = ((SourceListItem)item).Title;
// Return new view
return view;
}
public override bool ShouldSelectItem (NSOutlineView outlineView, Foundation.NSObject item)
{
return (outlineView.GetParent (item) != null);
}
public override void SelectionDidChange (NSNotification notification)
{
NSIndexSet selectedIndexes = _controller.SelectedRows;
// More than one item selected?
if (selectedIndexes.Count > 1) {
// Not handling this case
} else {
// Grab the item
var item = _controller.Data.ItemForRow ((int)selectedIndexes.FirstIndex);
// Was an item found?
if (item != null) {
// Fire the clicked event for the item
item.RaiseClickedEvent ();
// Inform caller of selection
_controller.RaiseItemSelected (item);
}
}
}
#endregion
}
}
這會提供來源清單的行為。
最後,在 方案總管 中,以滑鼠右鍵按兩下 [專案],然後選取 [新增>檔案...選取 [一般>空白類別],輸入 SourceListView
[名稱],然後按兩下 [新增] 按鈕。 SourceListView.cs
讓檔案看起來如下所示:
using System;
using AppKit;
using Foundation;
namespace MacOutlines
{
[Register("SourceListView")]
public class SourceListView : NSOutlineView
{
#region Computed Properties
public SourceListDataSource Data {
get {return (SourceListDataSource)this.DataSource; }
}
#endregion
#region Constructors
public SourceListView ()
{
}
public SourceListView (IntPtr handle) : base(handle)
{
}
public SourceListView (NSCoder coder) : base(coder)
{
}
public SourceListView (NSObjectFlag t) : base(t)
{
}
#endregion
#region Override Methods
public override void AwakeFromNib ()
{
base.AwakeFromNib ();
}
#endregion
#region Public Methods
public void Initialize() {
// Initialize this instance
this.DataSource = new SourceListDataSource (this);
this.Delegate = new SourceListDelegate (this);
}
public void AddItem(SourceListItem item) {
if (Data != null) {
Data.Items.Add (item);
}
}
#endregion
#region Events
public delegate void ItemSelectedDelegate(SourceListItem item);
public event ItemSelectedDelegate ItemSelected;
internal void RaiseItemSelected(SourceListItem item) {
// Inform caller
if (this.ItemSelected != null) {
this.ItemSelected (item);
}
}
#endregion
}
}
這會建立自定義且可重複使用的 NSOutlineView
子類別 ,SourceListView
我們可用來在我們所建立的任何 Xamarin.Mac 應用程式中驅動來源清單。
在 Xcode 中建立和維護來源清單
現在,讓我們在介面產生器中設計來源清單。 雙擊檔案以在介面產生器中開啟以進行編輯,並從連結Main.storyboard
庫偵測器拖曳分割檢視、將它新增至檢視控制器,並將它設定為使用 [條件約束編輯器] 中的 [檢視] 重設大小:
接下來,從 [鏈接庫偵測器] 拖曳 [來源列表],將它新增至 [分割檢視] 左側,並將它設定為使用 [條件約束編輯器] 中的 [檢視] 重設大小:
接下來,切換至 [身分識別檢視],選取 [來源清單],並將它變更為 [類別] :SourceListView
最後,為檔案中ViewController.h
呼叫SourceList
的來源清單建立輸出:
儲存變更並返回 Visual Studio for Mac 以與 Xcode 同步。
填入來源清單
讓我們在 Visual Studio for Mac 中編輯 RotationWindow.cs
檔案,讓它成為 AwakeFromNib
方法,如下所示:
public override void AwakeFromNib ()
{
base.AwakeFromNib ();
// Populate source list
SourceList.Initialize ();
var library = new SourceListItem ("Library");
library.AddItem ("Venues", "house.png", () => {
Console.WriteLine("Venue Selected");
});
library.AddItem ("Singers", "group.png");
library.AddItem ("Genre", "cards.png");
library.AddItem ("Publishers", "box.png");
library.AddItem ("Artist", "person.png");
library.AddItem ("Music", "album.png");
SourceList.AddItem (library);
// Add Rotation
var rotation = new SourceListItem ("Rotation");
rotation.AddItem ("View Rotation", "redo.png");
SourceList.AddItem (rotation);
// Add Kiosks
var kiosks = new SourceListItem ("Kiosks");
kiosks.AddItem ("Sign-in Station 1", "imac");
kiosks.AddItem ("Sign-in Station 2", "ipad");
SourceList.AddItem (kiosks);
// Display side list
SourceList.ReloadData ();
SourceList.ExpandItem (null, true);
}
在Initialize ()
新增任何專案之前,必須先針對來源清單的輸出呼叫 方法。 針對每個專案群組,我們會建立父專案,然後將子專案新增至該群組專案。 然後,每個群組都會新增至來源清單的集合 SourceList.AddItem (...)
。 最後兩行會載入來源清單的數據,並展開所有群組:
// Display side list
SourceList.ReloadData ();
SourceList.ExpandItem (null, true);
最後,編輯 AppDelegate.cs
檔案,並讓 DidFinishLaunching
方法看起來如下:
public override void DidFinishLaunching (NSNotification notification)
{
mainWindowController = new MainWindowController ();
mainWindowController.Window.MakeKeyAndOrderFront (this);
var rotation = new RotationWindowController ();
rotation.Window.MakeKeyAndOrderFront (this);
}
如果我們執行應用程式,將會顯示下列專案:
摘要
本文已詳細探討在 Xamarin.Mac 應用程式中使用來源清單。 我們已瞭解如何在 Xcode 的介面產生器中建立和維護來源清單,以及如何在 C# 程式代碼中使用源清單。