获取validateMenuItem:使用Xamarin生成的操作触发NSMenuItem

时间:2017-10-03 00:16:34

标签: c# xcode cocoa xamarin xamarin.mac

我想在我的上下文菜单中添加其他菜单项。理想情况下,使用validateMenuItem启用项目:

    [Action("validateMenuItem:")]
    public bool ValidateMenuItem(NSMenuItem item)
    {
        _logger.DebugFormat("Validating {0} menu item with Action {1}", item.Title, item.Action.Name);
        var target = item.Target;
        var menuItem = ViewModel.ContextMenu.Where(x => x.Title == item.Title).FirstOrDefault();
        if (menuItem != null) {
            return menuItem.Command.CanExecute();
        }

        return false; 
    }

https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/MenuList/Articles/EnablingMenuItems.html。如果我手动创建一个动作,则会调用它,但是如果我像这样分配一个事件处理程序:

            var nsMenuItem = new NSMenuItem(menuItem.Title,
                                            (sender, e) =>
            {
                menuItem.Command.ExecuteAsync();
            });
            nsMenuItem.Target = this;

validateMenuItem:不会被调用。使用此方法分配的Action是__monomac_internal_ActionDispatcher_activated:来自https://github.com/xamarin/xamarin-macios/blob/master/src/AppKit/ActionDispatcher.cs(请帮助我Rolf Bjarne Kvinge)。由于我的课程中没有这个动作(我认为),所以从不调用validateMenuItem,我的菜单项永远不会被激活。我怎样才能做到这一点?

更新。如果我将其添加到我的视图控制器,

    [Action("__monomac_internal_ActionDispatcher_activated:")]
    public void MonomacInternalAction(NSObject sender)
    {
    }

validateMenuItem:调用新项目。但是,事件处理程序将替换为此函数。 (这个问题可能无法解决!)这可能是导出与动作问题 - 我看到了

    const string skey = "__monomac_internal_ActionDispatcher_activated:";

    [Preserve, Export (skey)]
    public void OnActivated (NSObject sender)
    {
        EventHandler handler = Activated;
        if (handler != null)
            handler (sender, EventArgs.Empty);
    }

更新2。刚刚找到https://bugzilla.xamarin.com/show_bug.cgi?id=51343

更新3。我可以使用

欺骗validateMenuItem
    public override bool RespondsToSelector(ObjCRuntime.Selector sel)
    {
        if (sel.Name.Contains("__monomac_internal_ActionDispatcher_activated")) {
            return true;
        }
        return base.RespondsToSelector(sel);
    }

现在,如果我只能找到一种调用原始事件的方法!

1 个答案:

答案 0 :(得分:0)

此问题是Xamarin.Mac实施中的错误 - https://bugzilla.xamarin.com/show_bug.cgi?id=51343。我最终得到了一个解决方法。我没有为每个菜单项使用事件处理程序或单独的操作(无法确定如何注册),而是创建了一个处理所有菜单项的操作。

    [Action("contextAction:")]
    public void contextAction(NSObject sender)
    {
        if (sender is NSMenuItem)
        {
            var nsMenuItem = (NSMenuItem)sender;
            var wrapper = nsMenuItem.RepresentedObject as NSObjectWrapper;
            if (wrapper != null) {
                var menuItem = wrapper.Context as MenuItem;
                if (menuItem != null) {
                    menuItem.Command.ExecuteAsync();
                }
            }
        }
    }

然后

        foreach (var menuItem in ViewModel.ContextMenu)
        {
            var selector = new ObjCRuntime.Selector("contextAction:");
            var nsMenuItem = new NSMenuItem(menuItem.Title, selector, "");
            nsMenuItem.RepresentedObject = new NSObjectWrapper(menuItem);

NSObjectWrapper来自Monotouch: convert an Object to NSObject