Получение validateMenuItem: для запуска NSMenuItem с использованием действия, сгенерированного Xamarin.

Я хотел бы добавить дополнительные пункты меню в свое контекстное меню. В идеале элементы включаются с помощью 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: не вызывается. Действие, назначенное с помощью этого метода, — __monomac_internal_ActionDispatcher_activated: from https://github.com/xamarin/xamarin-macios/blob/master/src/AppKit/ActionDispatcher.cs (помогите мне, пожалуйста, Рольф Бьярне Квинге). Поскольку у меня нет этого действия в моем классе (я думаю), 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);
    }

теперь, если бы я только мог найти способ вызвать исходное событие!


person tofutim    schedule 03.10.2017    source источник


Ответы (1)


Эта проблема является ошибкой в ​​реализации 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: преобразовать объект в NSObject.

person tofutim    schedule 03.10.2017