簡體   English   中英

從 xib 文件加載視圖時獲取 System.InvalidCastException

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM