【问题标题】:Xamarin iOS: how to bind an extensions property?Xamarin iOS:如何绑定扩展属性?
【发布时间】:2017-08-03 15:12:09
【问题描述】:

我开始在我的 xamarin.ios 项目中使用 GitHub 的 SDAutoLayout library。 这个库有很多这个 UIView 类的扩展方法和属性。

我非常轻松地构建了绑定项目。
但是当我在我的项目中使用这个lib时,我发现所有的扩展属性在C#应用程序中都没有用。

然后,如果我将Sd_layout 的'get' 属性更改为方法--> SDAutoLayoutModel Sd_layout ();,运行时将抛出异常:

发送到类的无法识别的选择器
[类别]
[BaseType(typeof(UIView))]
界面 UIView_SDAutoLayout
{
// -(SDAutoLayoutModel *)sd_layout;
[静态]
[导出(“sd_layout”)]
SDAutoLayoutModel Sd_layout { get; }
..........

那么我应该如何在我的绑定项目中更改扩展属性,并将其用作我的xamarin.ios项目中的扩展方法`

【问题讨论】:

标签: c# xamarin properties xamarin.ios


【解决方案1】:

问题是属性/方法是[Static][Category]。绑定生成器尝试使用扩展方法(需要实例)或扩展类型(因为它是 UIKit 类型,所以它不能这样做)。

非 UIKit 基本类型

最简单的解决方案是强制生成器尽其所能,然后您可以提供帮助。可能有更好的方法,但这是可行的。

首先,将所有[Static] 成员移动到一个新类型中(如果它们都是静态的,则跳过这个)。使用用户友好的名称可能会很好,因为他们实际上会输入这个名称。在你的情况下,你可以使用SDAutoLayoutUIView 或其他东西。

然后,删除[Category] 属性,将[Static] 属性添加到,并确保[BaseType] 属性存在。

这将创建一个关于 class_ptr 不存在的编译器错误。这是因为该类别期望生成器做某事,但由于某种原因它没有......(听起来像一个错误。)

无论如何,只需创建一个包含单个成员的小类作为附加文件:

private static readonly IntPtr class_ptr = Class.GetHandle("UIView");

现在,一切都应该正常了。最终代码在Additions.cs中是这样的:

partial class SDAutoLayoutUIView
{
    private static readonly IntPtr class_ptr = Class.GetHandle("UIView");
}

你的绑定代码应该是这样的:

// ...

[Category]
[BaseType(typeof(UIView))]
interface UIView_SDAutoLayout
{
    // ... instance methods
}

[Static]
[BaseType(typeof(UIView))]
interface SDAutoLayoutUIView
{
    // ... static methods

    // -(SDAutoLayoutModel *)sd_layout;
    [Static]
    [Export("sd_layout")]
    SDAutoLayoutModel Sd_layout ();
}

// ...

应该这样做。这个选项很棒,因为我们只需要为一整套方法做一行。如果只有一两个,这实际上并没有那么大的优势,但仍然是更少的工作。

UIKit 基本类型

如果对象不是从UIView 继承的,上述方法可以正常工作。这是因为生成器为 UIKit 类做了额外的工作来获得外观位绑定。

如果是这种情况,您将不得不保留生成的绑定,但将其设为[Internal]。以下是更多信息:

https://github.com/xamarin/xamarin-macios/pull/1862

所以,你的绑定代码应该是这样的(原来是新的[Internal]):

[Category]
[BaseType(typeof(UIView))]
interface UIView_SDAutoLayout
{
    // -(SDAutoLayoutModel *)sd_layout;
    [Static]
    [Internal]
    [Export("sd_layout")]
    SDAutoLayoutModel Sd_layout();
}

但是,您的添加代码会正确执行:

partial class UIView_SDAutoLayout
{
    public static SDAutoLayoutModel Sd_layout()
    {
        // use the extension method
        return (null as UIView).Sd_layout();
    }
}

这很有效,因为我们向用户隐藏了奇怪的扩展方法,并将其包装成一个不需要空值的漂亮静态方法。实际上,这是工具的限制,因为它总是使用类别的扩展方法,但静态方法不能是 C# 中的扩展。

注意:您可能希望为该类使用一个好听的名称:SDAutoLayoutUIView

如果基类型是 UIKit 类型,例如 UIView,这很好。 (这也适用于任何类型,并且不限于 UIKit 类型。)但是,它确实需要将所有静态方法标记为内部方法,然后为每个方法创建正确的重载。如果你需要它们没问题,而且通常没有那么多事情要做。

拥有的基本类型

最好和最简单的情况是您拥有基本类型。例如,如果这是您的绑定:

[BaseType(typeof(UIView))]
interface MyThing
{
}

[Category]
[BaseType(typeof(MyThing))]
interface Others_MyThing
{
    [Static]
    [Export("createNewThing")]
    MyThing CreateNewThing ();
}

在这种情况下,只需简单地将成员移动到非类别类型中:

[BaseType(typeof(UIView))]
interface MyThing
{
    [Static]
    [Export("createNewThing")]
    MyThing CreateNewThing ();
}

[Category]
[BaseType(typeof(MyThing))]
interface Others_MyThing
{
}

【讨论】:

  • 啊嗨,我按照你的步骤做。它不能编译成功。错误消息是'SDAutoLayoutUIView':静态类不能用作约束。
  • 啊,如果类型继承自 UIView,我忘记了生成的外观类。让我编辑我的帖子...
  • 你好,@马修,我用你的新内部关键字来做这个,它编译成功。但是,它不是我的扩展方法。只是一个类的静态方法。你清楚我的情况吗是我的c#解决方案中必须使用IOS的扩展属性-(SDAutoLayoutModel *)sd_layout;作为扩展方法
  • This SDAutolayout library in GitHub I want to use in my xamarin.ios project。在项目的demo的第二页示例中。它教我如何在xcode项目中使用sd_layout ios'property。所以这对我来说在xamarin绑定项目中很困难
  • 您好@Matthew,您帮助我成功使用了我的 xamarin.ios 项目中的第三个库。您可以使用我们的评论上下文更新您的回答帖子,之后我会选择您的帖子作为真实的回答:)。非常感谢。
猜你喜欢
  • 1970-01-01
  • 2020-09-20
  • 2019-09-07
  • 1970-01-01
  • 2018-05-06
  • 2017-04-22
  • 2012-08-28
  • 2021-03-11
  • 1970-01-01
相关资源
最近更新 更多