[英]Getting System.InvalidCastException while loading View from a xib file
我有一個 xib 文件 - LoaderView.xib 和關聯的類 LoaderView.cs,其中包含一個用於顯示加載文本的視圖。 當我嘗試將它加載到主 ViewController 中時 -
public override void ViewDidAppear()
{
base.ViewDidAppear();
NSBundle.MainBundle.LoadNibNamed("LoaderView", this, out NSArray arr);
var view = Runtime.GetNSObject<LoaderView>(arr.ValueAt(0));
view.Frame = View.Frame;
View.AddSubview(view);
}
我在這一行中收到 System.InvalidCastException -
var view = Runtime.GetNSObject<LoaderView>(arr.ValueAt(0));
奇怪的是我每次都沒有得到異常。 當它工作時,我看到加載文本與默認視圖重疊 - 與 ViewController 相關聯。
有人可以指出顯示 Loading、Error 和 Empty 狀態的最佳方式是什么。 我應該為它們設置單獨的 ViewControllers 嗎? 或者我可以擁有可以從主視圖控制器加載/卸載的單獨的 xib 文件嗎? 如何從xib文件加載視圖?
問題出在 arr 中。
在上圖中,可以看出LoadNibNamed
方法並沒有每次都以相同的順序返回arr
中的頂級對象。 這就是為什么代碼 -
var view = Runtime.GetNSObject<LoaderView>(arr.ValueAt(0));
無法每次都將arr
的第 0 項轉換為LoaderView
類型。
解決方案是遍歷數組以找到您的類型的項目 - LoaderView
here。 就我而言 - 我寫了一個靜態類,它有一個通用方法LoadViewFromNib
,它返回一個從NSView
繼承的 T 類型的視圖。
public static class LoadNib
{
static NSArray xibItems;
static nuint index;
public static T LoadViewFromNib<T>(string filename, NSObject owner) where T : NSView
{
NSBundle.MainBundle.LoadNibNamed(filename, owner, out xibItems);
for (nuint i = 0; i < xibItems.Count; i++)
{
NSObject item = xibItems.GetItem<NSObject>(i);
if (item is T)
{
index = i;
break;
}
}
return Runtime.GetNSObject<T>(xibItems.ValueAt(index));
}
}
至於重疊問題,我發現除非明確設置其背景,否則子視圖是透明的。
這是 Xamarin 的文檔問題。 他們的文檔說使用第 0 個索引,但實際情況是數組順序不是確定性的。
Anagh 給出的答案是足夠的,並且在技術上是最佳的,但是您可以通過使用 Linq 使其更加簡潔,並且它也非常適合擴展方法:
public static class NibLoadingExtension
{
public static T LoadViewFromNib<T>(this T @null) where T : NSView
{
NSBundle.MainBundle.LoadNibNamed(typeof(T).Name, null, out var array);
return NSArray.FromArray<NSObject>(array).OfType<T>().FirstOrDefault();
}
}
不幸的是,由於你不能在沒有實例的情況下在 C# 中調用擴展方法,你必須像這樣使用它:
var loaderView = default(LoaderView).LoadViewFromNib();
還有一個論點支持向每個單獨的視圖類添加靜態 Create() 方法或其他內容,因為這樣您就可以調用私有初始化程序,如下所示:
public static LoaderView Create(ExampleDependency dependency)
{
var model = dependency ?? throw new ArgumentNullException(nameof(dependency));
NSBundle.MainBundle.LoadNibNamed(nameof(LoaderView), null, out var array);
var view = NSArray.FromArray<NSObject>(array).OfType<LoaderView>().FirstOrDefault();
view.Initialize(model);
return view;
}
private void Initialize(ExampleDependency dependency)
{
_privateField1 = dependency.Value1;
_privateField2 = dependency.Value2;
_privateField3 = dependency.Value3;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.