如何在 monoMac 中处理 NSTextField keyDown

Jes*_*sen 1 cocoa monomac xamarin

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

我创建了一个 NSTextFieldDelegate 派生类,并将编辑器委托设置为此类的一个实例。但是,我只看到调用了 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;
}
}
Run Code Online (Sandbox Code Playgroud)

知道我可能会错过什么吗?

编辑 2: 我刚刚注意到,如果我使用箭头键和向上/向下翻页,则会调用 DoCommandBySelector。仍然无法捕捉到 keydown 事件

Edit-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);
    }
}
Run Code Online (Sandbox Code Playgroud)

和输出。没有调用 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
Run Code Online (Sandbox Code Playgroud)

谢谢

Sus*_*ver 5

Cocoa 中的文本编辑与 WPF确实不同;-) NSTextField 和类似控件通常不处理实际编辑,因为使用了 NSTextView 字段编辑器......奇怪吗?取决于您如何看待它,对于 Windows 的样式控件,是的,对于 Cocoa,它是常态:

字段编辑器是一个由 NSWindow 维护的 NSTextView。字段编辑器会替换窗口中的任何 NSTextField 或 NSTextFieldCell 以进行编辑。

半必读材料:文本字段、文本视图和字段编辑器

NSTextField不响应 aKeyDown作为字段编辑器处理它和它提供的所有相关功能(单词完成、重音字母弹出等...,从而创建自定义NSTextField和覆盖KeyDownand KeyUp,只会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");
    }
Run Code Online (Sandbox Code Playgroud)

因此同样适用于NSTextFieldDelegate,你永远不会得到一个commandSelectorfor keydown/keyup...你得到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;
    }
Run Code Online (Sandbox Code Playgroud)

该怎么办?

首先你真的需要keydown吗?改变正常的 Cocoa UIX 不是常态,但如果你真的这样做了,一种方法是使用自定义NSTextView而不是 aNSTextField并且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");
    }
}
Run Code Online (Sandbox Code Playgroud)

如果你正在使用.xib你的界面设计,只需在 C# 中创建一个 NSTextView 子类,注册它,.h它将显示在 Xcode 中,并使用它用你的类替换 NSTextView。

根据您真正需要 keyDown 的用途,编辑开始/结束可能适用于您NSTextField

this.EditingBegan += (object sender, EventArgs e) => {
    Console.WriteLine("EditingBegan");
};
this.EditingEnded += (object sender, EventArgs e) => {
    Console.WriteLine("EditingEnded");
};
Run Code Online (Sandbox Code Playgroud)

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