如何在MonoTouch中代理UIKit代理?

时间:2013-02-09 20:27:00

标签: c# ios xamarin.ios uikit xamarin

我需要链接到UIScrollView的委托(它不在我的代码中,我无法控制它)并处理它的一些方法,同时将所有事件传递给前一个委托。

我的天真实现是这个代理类:

public class ScrollViewProxyDelegate : UIScrollViewDelegate
{
    private UIScrollViewDelegate _realDelegate;

    public ScrollViewProxyDelegate (UIScrollViewDelegate realDelegate)
    {
        _realDelegate = realDelegate;
    }

    public override void DecelerationStarted (UIScrollView scrollView)
    {
        _realDelegate.DecelerationStarted (scrollView);
    }

    public override void DecelerationEnded (UIScrollView scrollView)
    {
        _realDelegate.DecelerationEnded (scrollView);
    }

    // ...
 }

这没有用,因为我传递给scrollView.Delegate构造函数的ScrollViewProxyDelegate原来是null因为这个特定的委托在不同的类树中。我追求的属性是WeakDelegate,但它是NSObject

我看了this,我仍然感到困惑。我想我可以在每个方法中调用这个NSObject上的Objective C选择器,但是可能会有一个不那么详细的方法吗?

更新1

我刚尝试代理PerformSelectorRespondsToSelector,但却导致无法识别的选择器崩溃。

更新2

好的,显然是NSProxy is what people use for this。调查。

更新3

哎呀,MonoTouch中没有NSProxy

更新4

我最终使用键值观察来观看我的观点contentOffset。我应该早点考虑一下!不过,如果我需要它,我很好奇如何实现代理。

挂钩视图委托的最简单方法是什么?

1 个答案:

答案 0 :(得分:3)

如果您尝试代理的委托为空,或者您是否需要代理的委托是滚动视图的WeakDelegate,我不能完全遵循您对代理的需求吗?

WeakDelegate本质上是任何NSObject,您需要实现的任何方法都必须“导出”,以便委托的所有者能够调用它们。

[Export("scrollViewDidEndDecelerating:")]
public void MyDecelerationEndedMethod(UIScrollView scrollView)
{
  ...
}

您可以将这样的方法添加到任何NSObject,例如视图控制器。如果您需要使用WeakDelegate作为代理的主题,则必须查询它以查看它是否响应选择器然后执行选择器 - 我认为这就是您的意思。

但是,我认为您无法编写可以处理任何委托的通用代理,因为虽然代理调用了RespondsToSelector,但它没有调用PerformSelector - 选择器直接发送到代理并且不是通过PerformSelector。您必须编写一个代理,该代理实现与您要代理的委托完全相同的方法。

我能想出的最好的东西就像下面那样,你必须实现委托实现的每个方法。

public class TestProxy : NSObject
{
    private NSObject realDelegate;

    public TestProxy(NSObject realDelegate)
    {
        this.realDelegate = realDelegate;
    }

    public override bool RespondsToSelector(MonoTouch.ObjCRuntime.Selector sel)
    {
        Console.WriteLine("Query : " + sel.Name);
        return this.realDelegate.RespondsToSelector(sel);
    }

    [Export("tableView:didSelectRowAtIndexPath:")]
    public void RowSelected(UITableView tableView, NSIndexPath indexPath)
    {
        // invoke method on realDelegate either by casting to the correct type or by using
        // reflection to find the method that matches the export and pass this method's arguments.
        // which way you implement depends on your needs and what you know about the delegate being
        // proxied - casting would be much faster than reflection.
    }
}

因为您正在实现委托实现的所有方法,所以RespondsToSelector是冗余的而不是必需的。