【问题标题】:How to handle NSTextField keyDown in monoMac如何在 monoMac 中处理 NSTextField keyDown
【发布时间】:2016-01-07 23:22:59
【问题描述】:

我正在尝试使用 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;
}
}

知道我可能缺少什么吗?

Edit-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);
    }
}

和输出。不调用 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

谢谢

【问题讨论】:

  • 问题标题解决了“keyDown”问题,问题正文询问从未看到 DoCommandBySelector 方法被调用...您是在尝试捕获 NSTextField 上的 keydown 还是尝试让 DoCommandBySelector 触发?
  • 好吧,在阅读了其他一些帖子之后,似乎 doCommandBySelector 是这样做的方法。有没有其他方法可以做到这一点?我确实尝试派生 NSTextField 并覆盖 keyDown 但我(在某处)读到这不是正确的方法,而是应该通过委托处理。我(如您所知)是 Cocoa 的新手(WPF 背景)。
  • 另外你可能想看看创建一个自定义的NSFormatter.. 但同样,这取决于你想要用 KeyDown 控制...

标签: cocoa xamarin monomac


【解决方案1】:

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

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

半必读材料: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;
    }

怎么办?

首先你真的需要keydown吗?改变普通的 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 子类,注册它,.h 将显示在 Xcode 中,并使用它来用您的类替换 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:,过滤控件并仅在您感兴趣的控件时才做出反应...

【讨论】:

  • 哇,非常感谢您的详细描述。你是对的,我很可能不需要实际的 keyDown,我只需要能够过滤输入键。而且由于事实证明它不是那么直截了当,那么它可能不是正确的方法(不应该与框架对抗)。我会看看你推荐的阅读。感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-12
  • 1970-01-01
  • 1970-01-01
  • 2011-05-21
相关资源
最近更新 更多