如何在没有ViewController的情况下初始化由Interface Builder(由Xib支持)内置的可重用NSView

时间:2018-06-25 22:44:22

标签: macos cocoa nsview xamarin.mac

我试图建立一个可重用的视图,以便可以以编程方式实例化一个超级视图中的多个副本。但是,我想在Interface Builder中处理此可重用视图的约束和基本布局。对于我来说,我有一个NSViewController子类,一个NSView子类和一个xib文件。在我的ViewController的ViewDidLoad中,我有这样的代码来实例化子视图:

public override void ViewDidLoad()
{
    base.ViewDidLoad();

    var exampleView = new NSView();

    View.AddSubview(exampleView);
    View.AddConstraints(CreateExampleViewConstraints(exampleView, View));

    NSView lastView = null;
    foreach(var item in ExampleCollection)
    {
            var reuseableView = ReusableView.Create(item);
            reuseableView.TranslatesAutoresizingMaskIntoConstraints = false;

            exampleView.AddSubview(reuseableView);
            var xPosConstraint = NSLayoutConstraint.Create(reuseableView, NSLayoutAttribute.Left, NSLayoutRelation.Equal, exampleView, NSLayoutAttribute.Left, 1, 0);
            NSLayoutConstraint yPosConstraint = null;
            if(lastView != null)
            {
                yPosConstraint = NSLayoutConstraint.Create(reuseableView, NSLayoutAttribute.Top, NSLayoutRelation.Equal, lastView, NSLayoutAttribute.Bottom, 1, 0);
            }
            else
            {
                yPosConstraint = NSLayoutConstraint.Create(reuseableView, NSLayoutAttribute.Top, NSLayoutRelation.Equal, exampleView, NSLayoutAttribute.Top, 1, 0);
            }
            var widthConstraint = NSLayoutConstraint.Create(reuseableView, NSLayoutAttribute.Width, NSLayoutRelation.Equal, exampleView, NSLayoutAttribute.Width, 1, 0);
            var heightConstraint = NSLayoutConstraint.Create(reuseableView, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1, 142);
            exampleView.AddConstraint(xPosConstraint);
            exampleView.AddConstraint(yPosConstraint);
            exampleView.AddConstraint(widthConstraint);
            exampleView.AddConstraint(heightConstraint);

            lastView = reuseableView;
        }
    }

    if(lastView != null)
    {
        var bottomPinConstraint = NSLayoutConstraint.Create(exampleView, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, lastView, NSLayoutAttribute.Bottom, 1, 0);
        exampleView.AddConstraint(bottomPinConstraint);
    }
}

对于我要解决的问题,约束并不重要。 ReusableViewNSView的子类,它有3个NSTextFieldTitleLabelDateLabel的{​​{1}}出口:

LocationLabel

我遇到的问题是:在显示之前,ViewController的生命周期方法中的任何时候都不会钩住ReusableView的IBOutlet /而不是null。如您所见,我有一个名为public partial class ReusableView : AppKit.NSView { string _title; string _date; string _location; public ReusableView(IntPtr handle) : base(handle) { } [Export("initWithCoder:")] public ReusableView(NSCoder coder) : base(coder) { } public static ReusableView Create(ExampleDependency dependency) { var model = dependency ?? throw new ArgumentNullException(nameof(dependency)); NSBundle.MainBundle.LoadNibNamed(nameof(ReusableView), null, out var array); var view = NSArray.FromArray<NSObject>(array).OfType<ReusableView>().FirstOrDefault(); view.Initialize(model); return view; } private void Initialize(ExampleDependency dependency) { _title = dependency.name; _date = dependency.date; _location = $"{dependency.eventCity}, {dependency.eventState}"; } public void UpdateControls() { TitleLabel.StringValue = _title; DateLabel.StringValue = _date; LocationLabel.StringValue = _location; } } 的公用方法,它试图根据在UpdateControls()期间初始化的私有字段来设置标签的初始值。 Create()方法确实成功加载了xib并返回了Create()的实例;我什至可以在运行时看到视图和占位符值。但是,我曾尝试在Superview的视图控制器的ReusableViewUpdateControls()方法期间调用AwakeFromNib(),但始终会得到一个空引用异常,因为显然没有实例化这些出口。 / p>

我显然可以完全以编程方式创建ReusableView并在代码中设置控件的约束,但是我试图利用接口构建器。有办法吗?

1 个答案:

答案 0 :(得分:0)

如果不为我的可重用视图添加视图控制器,就无法使它正常工作。在Xamarin中,我使用了Mac > View with Controller模板,并在生成的xib文件中列出了所有约束。然后,在我更改的代码中:

var reuseableView = ReusableView.Create(item);
reuseableView.TranslatesAutoresizingMaskIntoConstraints = false;

exampleView.AddSubview(reuseableView);

收件人:

var reusableViewController = new ReuseableViewController(item);
var reuseableView = reusableViewController.View;
reuseableView.TranslatesAutoresizingMaskIntoConstraints = false;

exampleView.AddSubview(reuseableView);

访问View上的强类型ReuseableViewController属性可确保将xib装入并连接插座。在ReuseableViewController代码中,我有以下内容:

// Call to load from the XIB/NIB file
public ReuseableViewController(ExampleDependency dependency) : base("ReuseableViewController", NSBundle.MainBundle)
{
    _dependency = dependency;
}

public override void ViewDidLoad()
{
    base.ViewDidLoad();

    if(_dependency != null)
    {
        TitleLabel.StringValue = _dependency.name;
        DateLabel.StringValue = _dependency.date;
        LocationLabel.StringValue = $"{_dependency.eventCity}, {_dependency.eventState}";
    }
}

我对这个答案不是100%满意的,因为我认为View Controller对于代码重用来说不是必需的,因此,如果其他人有更好的答案,请继续进行回答。