【问题标题】:Getting System.InvalidCastException while loading View from a xib file从 xib 文件加载视图时获取 System.InvalidCastException
【发布时间】:2018-02-20 05:45:11
【问题描述】:

我有一个 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 关联。

谁能指出显示加载、错误和空状态的最佳方式是什么。我应该为他们设置单独的 ViewControllers 吗?或者我可以有单独的 xib 文件,我可以从主视图控制器加载/卸载吗?如何从 xib 文件加载视图?

【问题讨论】:

    标签: c# macos xamarin xib nsview


    【解决方案1】:

    问题在于arr。

    在上面的图片中,可以看出LoadNibNamed 方法每次都没有以相同的顺序返回arr 中的顶级对象。这就是为什么代码 -

    var view = Runtime.GetNSObject<LoaderView>(arr.ValueAt(0));
    

    无法每次都将arr 的第0 项转换为LoaderView

    解决方案是遍历数组以找到您的类型的项目 - LoaderView 这里。就我而言 - 我写了一个静态类,它有一个泛型方法 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));
        }
    }
    

    至于重叠问题,我发现子视图是透明的,除非它的背景被明确设置。

    【讨论】:

      【解决方案2】:

      这是 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;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-09-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多