0

我使用 NSOutlineView 在我的 C#/MonoMac 应用程序中创建了一个侧边栏,并获得了创建问题Create NSView programmatically in Xamarin Studio中的项目的帮助。但是现在我已经使大纲视图中的一些项目可编辑,当然我想检测项目何时被编辑并采取行动(编辑底层模型,或者如果编辑了特殊的“创建新”项目,则创建一个新模型)。

这些项目可以通过双击或在选中时按回车进行编辑。但我不知道如何检测何时在我的代码中编辑了项目。我试图在我的 NSOutlineViewDataSource 中覆盖 CommitEditing,并在我的 NSOutlineViewDelegate 中覆盖 CommitEditing 和 ShouldEditTableColumn。这些似乎都没有被调用。

我还尝试将 EditingEnded 的事件处理程序连接到 NSTextField,这是我在 NSOutlineViewDelegate.GetView 方法中调用 MakeView 时获得的视图的子视图。但这会使应用程序崩溃。当我尝试设置 NSTextField 的委托并在其中覆盖 EditingEnded 或 TextShouldEndEditing 时,我也会崩溃。进入编辑模式后,只要我按下一个键,就会发生崩溃。

现在我迷路了。感觉好像我什么都试过了。

如果您想查看这里的代码:

模型:https ://code.google.com/p/yet-another-music-application/source/browse/trunk/Player/GUIs/OSX/Models/Navigation.cs

视图控制器:https ://code.google.com/p/yet-another-music-application/source/browse/trunk/Player/GUIs/OSX/Views/NavigationViewController.cs

这是我使用此代码订阅 Changed 事件时的崩溃:

    // ...
    view = outlineView.MakeView ("DataCell", this);
    ((NSTextField)view.Subviews [1]).Changed += foo;
}

private void foo(object sender, EventArgs e) {
    Console.WriteLine("changed text field.");
};
2013-08-02 08:53:32.851 Stoffi[6582:1007]-[__NSCFType controlTextDidEndEditing:]:无法识别的选择器发送到实例 0x16a6c40
2013-08-02 08:53:32.852 Stoffi [6582:1007] 处理键输入时检测到异常。
2013-08-02 08:53:32.852 Stoffi[6582:1007]-[__NSCFType controlTextDidEndEditing:]:无法识别的选择器发送到实例 0x16a6c40
2013-08-02 08:53:32.863 斯托菲[6582:1007] (
    0 核心基础 0x9966be8b __raiseError + 219
    1 libobjc.A.dylib 0x98a8f52e objc_exception_throw + 230
    2核心基础0x9966fafd-[NSObject(NSObject)不识别选择器:]+253
    3 核心基础 0x995b7e87 ___转发___ + 487
    4 核心基础 0x995b7c32 _CF_forwarding_prep_0 + 50
    5 基础 0x93d36e52 __57-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke_0 + 49
    6 核心基础 0x9962d851 ___CFXNotificationPost_block_invoke_0 + 257
    7 核心基础 0x99578e8a _CFXNotificationPost + 2794
    8 基础 0x93d1f988 -[NSNotificationCenter postNotificationName:object:userInfo:] + 92
    9 AppKit 0x972b9926-[NSTextField textDidEndEditing:] + 405
    10 基础 0x93d36e52 __57-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke_0 + 49
    11 核心基础 0x9962d851 ___CFXNotificationPost_block_invoke_0 + 257
    12 核心基础 0x99578e8a _CFXNotificationPost + 2794
    13 基础 0x93d1f988 -[NSNotificationCenter postNotificationName:object:userInfo:] + 92
    14 AppKit 0x96fd762b-[NSTextView(NSPrivate)_giveUpFirstResponder:] + 434
    15 AppKit 0x96fd746f-[NSTextView(NSKeyBindingCommands) insertNewline:] + 580
    16 libobjc.A.dylib 0x98a9c5d3-[NSObject performSelector:withObject:] + 70
    17 AppKit 0x96fd714e-[NSResponder doCommandBySelector:] + 91
    18 AppKit 0x96fd6f83-[NSTextView doCommandBySelector:] + 152
    19 AppKit 0x97067fe3-[NSTextInputContext doCommandBySelector:] + 121
    20 AppKit 0x97067f5d-[NSTextInputContext _handleCommand:] + 84
    21 AppKit 0x97062929-[NSKeyBindingManager(NSKeyBindingManager_MultiClients) 解释EventAsCommand:forClient:] + 2006
    22 AppKit 0x97061db5-[NSTextInputContext 句柄事件:] + 1298
    23 AppKit 0x97061825-[NSView 解释键事件:] + 205
    24 AppKit 0x96fa43b8-[NSTextView keyDown:] + 680
    25 AppKit 0x971c8af1 -[NSWindow 发送事件:] + 7432
    26 AppKit 0x971c390f -[NSApplication 发送事件:] + 4278
    27 AppKit 0x970dd62c -[NSApplication 运行] + 951
    28 AppKit 0x970805f6 NSApplicationMain + 1053
    29 ???0x060c9e76 0x0 + 101490294
    30 ???0x060c9c70 0x0 + 101489776
    31 ???0x007beff8 0x0 + 8122360
    32 ???0x007bf156 0x0 + 8122710
    33 libmono-2.0.dylib 0x0100be52 mono_jit_runtime_invoke + 722
    34 libmono-2.0.dylib 0x011a767a mono_runtime_invoke + 170
    35 libmono-2.0.dylib 0x011aa1f1 mono_runtime_exec_main + 705
    36 libmono-2.0.dylib 0x011a9401 mono_runtime_run_main + 929
    37 libmono-2.0.dylib 0x010695e5 mono_jit_exec + 149
    38 libmono-2.0.dylib 0x0106bb79 mono_main + 9609
    39 斯托菲 0x0000308f 主要 + 2047
    40 斯托菲 0x00002885 开始 + 53
)
4

1 回答 1

2

在里面的文本字段上订阅事件对GetView我来说很好。该问题必须存在于您的代码中的其他位置...


编辑添加:

小心做这样的事情:

((NSTextField)view.Subviews [1]).Delegate = new PlaylistNavigationDelegate ();

并且,根据您最初的尝试将事件分配给匿名方法。

在这种情况下,一旦控制离开 的范围GetView,对您的委托的唯一引用就在非托管端。Mono GC 看不到这一点,并且委托有资格被收集。当托管引用是从 Cocoa 下收集的垃圾时,这可能会导致各种问题。


工作样本:

// MainWindowController...

        public override void AwakeFromNib()
        {
            rootNode = new Node(new NSString("Root Node"));

            for(int i = 1; i <=5; i++)
            {
                rootNode.Children.Add(new Node(new NSString("Child Node")));
            }

            sourceList.Delegate = new SourceListDelegate(this);
            sourceList.DataSource = new SourceListDataSource(this);

            base.AwakeFromNib();
        }

        private class SourceListDataSource : NSOutlineViewDataSource
        {
            private MainWindowController controller;

            public SourceListDataSource(MainWindowController controller)
            {
                this.controller = controller;
            }

            public override int GetChildrenCount(NSOutlineView outlineView, NSObject item)
            {
                if(item != null)
                {
                    return (int)((Node)item).Count;
                }

                return (int)controller.rootNode.Count;
            }

            public override bool ItemExpandable(NSOutlineView outlineView, NSObject item)
            {
                if(item == null)
                {
                    return false;
                }

                return !((Node)item).Leaf;
            }

            public override NSObject GetChild(NSOutlineView outlineView, int childIndex, NSObject item)
            {
                if(item == null)
                {
                    return (Node)Runtime.GetNSObject(controller.rootNode.Children.ValueAt((uint)childIndex));
                }

                Node theItem = (Node)item;
                return (Node)Runtime.GetNSObject(theItem.Children.ValueAt((uint)childIndex));
            }

            public override NSObject GetObjectValue(NSOutlineView outlineView, NSTableColumn tableColumn, NSObject item)
            {
                if(item != null)
                {
                    return ((Node)item).Text;
                }

                return new NSString("");
            }
        }

        private class SourceListDelegate : NSOutlineViewDelegate
        {
            private MainWindowController controller;

            public SourceListDelegate(MainWindowController controller)
            {
                this.controller = controller;
            }

            public override bool IsGroupItem(NSOutlineView outlineView, NSObject item)
            {
                return (Node)item == controller.rootNode;
            }

            public override bool ShouldEditTableColumn(NSOutlineView outlineView, NSTableColumn tableColumn, NSObject item)
            {
                return true;
            }

            public override NSView GetView(NSOutlineView outlineView, NSTableColumn tableColumn, NSObject item)
            {
                if(IsGroupItem(outlineView, item))
                {
                    return outlineView.MakeView("HeaderCell", this);
                }

                var view = outlineView.MakeView("DataCell", this);
                var node = (Node)item;

                ((NSTextField)view.Subviews[1]).StringValue = node.Text;
                ((NSTextField)view.Subviews[1]).Changed += HandleChanged;

                return view;
            }

            void HandleChanged (object sender, EventArgs e)
            {
                Console.WriteLine("changed");
            }
        }

        private class Node : NSObject
        {
            private NSMutableArray children = new NSMutableArray();

            public NSMutableArray Children
            {
                get
                {
                    return children;
                }
            }

            public uint Count
            {
                get
                {
                    return Children.Count;
                }
            }

            public bool Leaf
            {
                get
                {
                    return this.Count == 0;
                }
            }

            public NSString Text { get; set; }

            public Node(NSString text)
            {
                this.Text = text;
            }
        }
于 2013-08-02T12:44:42.603 回答