Reputation: 1969
I'm trying to handle the keyDown event for NSTextField using monoMac and Xamarin Studio.
I have created a NSTextFieldDelegate derived class and set the editors delegate to an instance of this class. However, I only see the Changed method being called, never the 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;
}
}
Any idea what I might be missing ?
Edit-2: I just noticed that DoCommandBySelector is being called if I use the arrow keys and page up/down. Still not able to catch the keydown event
Edit-1: I tried to make a small project with Xamarin.mac, just 2 edit fields, with a derived edit control and the delegate.
This is the code
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);
}
}
and the output. No call to keyDown or DoCommandBySelector. I must be missing something very basic
1-EditingBegan
1-changed
KeyUp
1-changed
KeyUp
1-changed
KeyUp
1-EditingEnded
2-EditingBegan
2-changed
KeyUp
2-changed
KeyUp
2-changed
KeyUp
Thanks
Upvotes: 1
Views: 1446
Reputation: 74174
Text editing is in Cocoa is really different than WPF ;-) NSTextField and like controls normally do not deal with the actual editing as a NSTextView field editor is used... Strange? Depends upon on how you look at it, for Windows' style controls yes, for Cocoa it is the norm:
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 Reading material : Text Fields, Text Views, and the Field Editor
NSTextField
does not respond to a KeyDown
as the field editor handles it and all the related functions that it provides (word completion, accent letter popups, etc..., and thus creating a custom NSTextField
and overriding KeyDown
and KeyUp
, only KeyUp
will be called:
public override void KeyDown(NSEvent theEvent)
{
throw new Exception("NSTextField KeyDown never gets called");
}
public override void KeyUp(NSEvent theEvent)
{
Console.WriteLine("NSTextField KeyUp");
}
Thus the same goes for NSTextFieldDelegate
, you will never get a commandSelector
for keydown/keyup... you will get insertNewline:
, cancelOperation:
, deleteBackward:
, etc...
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;
}
First do you really need keydown? Altering the normal Cocoa UIX is not the norm, but if you really do, one way is to use a custom NSTextView
instead of a NSTextField
and the KeyDown
override will be called:
[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");
}
}
If you are using .xib
for your interface design, just create a NSTextView subclass in C#, register it and the .h
will show up in Xcode and use it to replace the NSTextView with your class.
Depending on what you really need keyDown for, maybe editing begin/end will work for your NSTextField
:
this.EditingBegan += (object sender, EventArgs e) => {
Console.WriteLine("EditingBegan");
};
this.EditingEnded += (object sender, EventArgs e) => {
Console.WriteLine("EditingEnded");
};
You can also hook that NSWindow's field editor and listen for all keyDown:
, filter the controls and only react if it is a control that you are interested in...
Upvotes: 5