如何在 monoMac 中处理 NSTextField keyDown

How to handle NSTextField keyDown in monoMac

我正在尝试使用 monoMac 和 Xamarin Studio 处理 NSTextField 的 keyDown 事件。

我创建了一个派生的 NSTextFieldDelegate class 并将编辑器委托设置为此 class 的一个实例。但是,我只看到被调用的 Changed 方法,从来没有看到 DoCommandBySelector

class TextPathDelegate : NSTextFieldDelegate {
public override void Changed(NSNotification notification)
{
    Console.WriteLine("changed");
}
public override void DidChangeValue(string forKey)
{
    Console.WriteLine("didchange = {0}", forKey);
}
public override void WillChangeValue(string forKey)
{
    Console.WriteLine("willchange = {0}", forKey);
}

public override bool DoCommandBySelector(NSControl control, NSTextView textView, MonoMac.ObjCRuntime.Selector commandSelector)
{
    Console.WriteLine("DoCommandBySelector = {0}", commandSelector.ToString());
    return false;
}
}

知道我可能遗漏了什么吗?

编辑 2: 我刚刚注意到,如果我使用箭头键和页面 up/down,就会调用 DoCommandBySelector。仍然无法捕获按键事件

编辑-1: 我尝试用 Xamarin.mac 制作一个小项目,只有 2 个编辑字段,带有派生的编辑控件和委托。

这是代码

class TextPathDelegate : NSTextFieldDelegate {
    string Id { get; set; }
    public TextPathDelegate(string id) { Id = id; }
    public override void Changed(NSNotification notification)
    {
        Console.WriteLine(Id + "changed");
    }
    public override bool DoCommandBySelector(NSControl control, NSTextView textView, ObjCRuntime.Selector commandSelector)
    {
        Console.WriteLine(Id + "DoCommandBySelector = {0}", commandSelector.ToString());
        return false;
    }
    public override void EditingBegan(NSNotification notification)
    {
        Console.WriteLine(Id + "EditingBegan");
    }
    public override void EditingEnded(NSNotification notification)
    {
        Console.WriteLine(Id + "EditingEnded");
    }
}

[Register("MyNSTextField")]
class MyNSTextField : NSTextField {
    public MyNSTextField(IntPtr handle) : base(handle){}
    public override void KeyDown(NSEvent theEvent)
    {
        Console.WriteLine("KeyDown");
        base.KeyDown(theEvent);
    }
    public override void KeyUp(NSEvent theEvent)
    {
        Console.WriteLine("KeyUp");
        base.KeyUp(theEvent);
    }
}

和输出。不调用 keyDown 或 DoCommandBySelector。我一定是遗漏了一些非常基本的东西

1-EditingBegan
1-changed
KeyUp
1-changed
KeyUp
1-changed
KeyUp
1-EditingEnded
2-EditingBegan
2-changed
KeyUp
2-changed
KeyUp
2-changed
KeyUp

谢谢

Cocoa 中的文本编辑与 WPF 真的 不同;-) NSTextField 和类似控件通常不处理实际编辑,因为 NSTextView 字段编辑器是用过……奇怪?取决于你如何看待它,对于 Windows' 样式控件是的,对于 Cocoa 它是标准的:

Field editor is an NSTextView which is maintained by NSWindow. The field editor replaces any NSTextField or NSTextFieldCell in the window for editing purposes.

Semi-required 阅读 material : Text Fields, Text Views, and the Field Editor

NSTextField 不响应 KeyDown,因为 字段编辑器处理它 及其提供的所有相关功能(单词完成、重音字母弹出窗口等...,从而创建自定义 NSTextField 并覆盖 KeyDownKeyUp,只有 KeyUp 会被调用:

    public override void KeyDown(NSEvent theEvent)
    {
        throw new Exception("NSTextField KeyDown never gets called");
    }

    public override void KeyUp(NSEvent theEvent)
    {
        Console.WriteLine("NSTextField KeyUp");
    }

因此 NSTextFieldDelegate 也是如此,你永远不会得到 keydown/keyup 的 commandSelector...你 得到 insertNewline:cancelOperation:deleteBackward:、等等……

    public override void Changed(NSNotification notification)
    {
        Console.WriteLine("changed"); // after the field editor is done
    }

    public override bool DoCommandBySelector(NSControl control, NSTextView textView, Selector commandSelector)
    {
        Console.WriteLine("DoCommandBySelector = {0}", commandSelector.Name);
        return false;
    }

怎么办?

首先你真的需要按键吗?改变正常的 Cocoa UIX 不是标准,但如果你真的这样做,一种方法是使用自定义 NSTextView 而不是 NSTextField 并且 KeyDown 覆盖将是叫:

[Register("CustomTextView")]
public class CustomTextView : NSTextView
{
    public CustomTextView() : base() {
        Console.WriteLine("CustomTextView");
    }
    public CustomTextView(IntPtr handle) : base(handle) {
        Console.WriteLine("CustomTextView IntPtr");
    }
    [Export("initWithCoder:")]
    public CustomTextView(NSCoder coder) : base(coder) {
        Console.WriteLine("CustomTextView initWithCoder");
    }
    public override void KeyDown(NSEvent theEvent) {
        Console.WriteLine("CustomTextView KeyDown");
    }
    public override void KeyUp(NSEvent theEvent) {
        Console.WriteLine("CustomTextView KeyUp");
    }
}

如果您使用 .xib 进行界面设计,只需在 C# 中创建一个 NSTextView subclass,注册它,.h 将显示在 Xcode 中并使用它用您的 class.

替换 NSTextView

根据您真正需要 keyDown 的目的,编辑 begin/end 可能对您的 NSTextField:

有用
this.EditingBegan += (object sender, EventArgs e) => {
    Console.WriteLine("EditingBegan");
};
this.EditingEnded += (object sender, EventArgs e) => {
    Console.WriteLine("EditingEnded");
};

您还可以挂钩 NSWindow 的字段编辑器并监听所有 keyDown:、过滤控件并仅在它是您感兴趣的控件时做出反应...