#define EVT_DATAVIEW_COLUMN_HEADER_RIGHT_CLICKED(id, fn) wx__DECLARE_DATAVIEWEVT(COLUMN_HEADER_RIGHT_CLICK, id, fn)
 #define EVT_DATAVIEW_COLUMN_SORTED(id, fn) wx__DECLARE_DATAVIEWEVT(COLUMN_SORTED, id, fn)
 
-#define EVT_DATAVIEW_MODEL_ITEM_ADDED(id, fn) wx__DECLARE_DATAVIEWEVT(MODEL_ITEM_APPENDED, id, fn)
+#define EVT_DATAVIEW_MODEL_ITEM_ADDED(id, fn) wx__DECLARE_DATAVIEWEVT(MODEL_ITEM_ADDED, id, fn)
 #define EVT_DATAVIEW_MODEL_ITEM_DELETED(id, fn) wx__DECLARE_DATAVIEWEVT(MODEL_ITEM_DELETED, id, fn)
 #define EVT_DATAVIEW_MODEL_ITEM_CHANGED(id, fn) wx__DECLARE_DATAVIEWEVT(MODEL_ITEM_CHANGED, id, fn)
 #define EVT_DATAVIEW_MODEL_VALUE_CHANGED(id, fn) wx__DECLARE_DATAVIEWEVT(MODEL_VALUE_CHANGED, id, fn)
 
     void OnPrependList(wxCommandEvent& event);
     void OnDeleteList(wxCommandEvent& event);
 
+    void OnValueChanged( wxDataViewEvent &event );
+    void OnItemAdded( wxDataViewEvent &event );
+    void OnItemDeleted( wxDataViewEvent &event );
+
 private:
     wxDataViewCtrl* m_musicCtrl;
     wxObjectDataPtr<MyMusicModel> m_music_model;
     ID_ABOUT = wxID_ABOUT,
     ID_EXIT = wxID_EXIT,
     
+    ID_MUSIC_CTRL       = 50,
+    
     ID_ADD_MOZART       = 100,
     ID_DELETE_MUSIC     = 101,
      
     EVT_BUTTON( ID_DELETE_MUSIC, MyFrame::OnDeleteMusic )
     EVT_BUTTON( ID_PREPEND_LIST, MyFrame::OnPrependList )
     EVT_BUTTON( ID_DELETE_LIST, MyFrame::OnDeleteList )
+    EVT_DATAVIEW_MODEL_ITEM_ADDED( ID_MUSIC_CTRL, MyFrame::OnItemAdded )
+    EVT_DATAVIEW_MODEL_ITEM_DELETED( ID_MUSIC_CTRL, MyFrame::OnItemDeleted )
+    EVT_DATAVIEW_MODEL_VALUE_CHANGED( ID_MUSIC_CTRL, MyFrame::OnValueChanged )
 END_EVENT_TABLE()
 
 MyFrame::MyFrame(wxFrame *frame, wxChar *title, int x, int y, int w, int h):
   wxFrame(frame, wxID_ANY, title, wxPoint(x, y), wxSize(w, h))
 {
+    m_log = NULL;
+
     SetIcon(wxICON(sample));
 
     // build the menus:
 
     // MyMusic
 
-    m_musicCtrl = new wxDataViewCtrl( this, wxID_ANY, wxDefaultPosition,
+    m_musicCtrl = new wxDataViewCtrl( this, ID_MUSIC_CTRL, wxDefaultPosition,
                                     wxDefaultSize );
 
     m_music_model = new MyMusicModel;
         m_list_model->DeleteItem( item );
 }
 
+void MyFrame::OnItemAdded( wxDataViewEvent &event )
+{
+    if (!m_log)
+        return;
+        
+    m_log->AppendText( "EVT_DATAVIEW_MODEL_ITEM_ADDED\n" );
+}
+
+void MyFrame::OnItemDeleted( wxDataViewEvent &event )
+{
+    if (!m_log)
+        return;
+        
+    m_log->AppendText( "EVT_DATAVIEW_MODEL_ITEM_DELETED\n" );
+}
+
+void MyFrame::OnValueChanged( wxDataViewEvent &event )
+{
+    if (!m_log)
+        return;
+        
+    m_log->AppendText( "EVT_DATAVIEW_MODEL_VALUE_CHANGED\n" );
+}
+
 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event) )
 {
     wxAboutDialogInfo info;
 
     SetHidden((flags & wxDATAVIEW_COL_HIDDEN) != 0);
 }
 
-// ---------------------------------------------------------
-// wxDataViewEventModelNotifier
-// ---------------------------------------------------------
-
-class WXDLLIMPEXP_ADV wxDataViewEventModelNotifier: public wxDataViewModelNotifier
-{
-public:
-    wxDataViewEventModelNotifier( wxDataViewCtrl *ctrl ) { m_ctrl = ctrl; }
-    
-    bool SendEvent( wxEventType event_type, const wxDataViewItem &item, unsigned int col = 0 )
-    {
-        wxDataViewEvent event( event_type, m_ctrl->GetId() );
-        event.SetEventObject( m_ctrl );
-        event.SetModel( m_ctrl->GetModel() );
-        event.SetItem( item );
-        event.SetColumn( col );
-        m_ctrl->GetEventHandler()->ProcessEvent( event );
-        return true;
-    }
-
-    virtual bool ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item )  
-        { return SendEvent( wxEVT_COMMAND_DATAVIEW_MODEL_ITEM_ADDED, item ); }
-    virtual bool ItemDeleted( const wxDataViewItem &item )
-        { return SendEvent( wxEVT_COMMAND_DATAVIEW_MODEL_ITEM_DELETED, item ); }
-    virtual bool ItemChanged( const wxDataViewItem &item )
-        { return SendEvent( wxEVT_COMMAND_DATAVIEW_MODEL_ITEM_CHANGED, item ); }
-    virtual bool ValueChanged( const wxDataViewItem &item, unsigned int col )
-        { return SendEvent( wxEVT_COMMAND_DATAVIEW_MODEL_VALUE_CHANGED, item, col ); }
-    virtual bool Cleared()      
-        { return SendEvent( wxEVT_COMMAND_DATAVIEW_MODEL_CLEARED, wxDataViewItem(0) ); }
-
-private:
-    wxDataViewCtrl *m_ctrl;
-};
-
-
 // ---------------------------------------------------------
 // wxDataViewCtrlBase
 // ---------------------------------------------------------
 {
     m_model = NULL;
     m_cols.DeleteContents( true );
-    m_eventNotifier = NULL;
     m_expander_column = 0;
     m_indent = 8;
 }
 
     if (m_model)
     {
-        if (m_eventNotifier)
-            m_model->RemoveNotifier( m_eventNotifier );
-        m_eventNotifier = NULL;
-    
         m_model->DecRef();
         m_model = NULL;
     }
 {
     if (m_model)
     {
-        if (m_eventNotifier)
-            m_model->RemoveNotifier( m_eventNotifier );
-        m_eventNotifier = NULL;
-        
         m_model->DecRef();   // discard old model, if any
     }
 
     if (m_model)
     {
         m_model->IncRef(); 
-        m_eventNotifier = new wxDataViewEventModelNotifier( (wxDataViewCtrl*) this );
-        m_model->AddNotifier( m_eventNotifier );
     }
 
     return true;
 
 
     bool ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item );
     bool ItemDeleted( const wxDataViewItem &item );
-    
+    bool ItemChanged( const wxDataViewItem &item );
+    bool ValueChanged( const wxDataViewItem &item, unsigned int col );
+    bool Cleared();
     void Resort();
     
 protected:
         GTK_TREE_MODEL(m_wxgtk_model), path, &iter );
     gtk_tree_path_free (path);
 
+    m_owner->GtkGetInternal()->ItemChanged( item );
+    
     return true;
 }
 
             // Redraw
             gtk_widget_queue_draw_area( GTK_WIDGET(widget),
                 cell_area.x - xdiff, ydiff + cell_area.y, cell_area.width, cell_area.height );
+                
+            m_owner->GtkGetInternal()->ValueChanged( item, model_col );
+            
+            return true;
         }
     }
 
-    return true;
+    return false;
 }
 
 bool wxGtkDataViewModelNotifier::Cleared()
 {
+    // TODO: delete everything
+
+    m_owner->GtkGetInternal()->Cleared();
+    
     return false;
 }
 
 
 void wxDataViewCtrlInternal::BuildBranch( wxGtkTreeModelNode *node )
 {
+    wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_MODEL_ITEM_ADDED, m_owner->GetId() );
+    event.SetEventObject( m_owner );
+    event.SetModel( m_owner->GetModel() );
+
     if (node->GetChildCount() == 0)
     {
         wxDataViewItem child = m_wx_model->GetFirstChild( node->GetItem() );
                 node->AddNode( new wxGtkTreeModelNode( node, child, this ) );
             else
                 node->AddLeave( child.GetID() );
+                
+            event.SetItem( child );
+            m_owner->GetEventHandler()->ProcessEvent( event );
+    
             child = m_wx_model->GetNextSibling( child );
         }
     }
         parent_node->AddNode( new wxGtkTreeModelNode( parent_node, item, this ) );
     else
         parent_node->AddLeave( item.GetID() );
+        
+    wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_MODEL_ITEM_ADDED, m_owner->GetId() );
+    event.SetEventObject( m_owner );
+    event.SetModel( m_owner->GetModel() );
+    event.SetItem( item );
+    m_owner->GetEventHandler()->ProcessEvent( event );
+
     return true;
 }
 
 {
     wxGtkTreeModelNode *parent = FindParentNode( item );
     parent->DeleteChild( item.GetID() );
+    
+    wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_MODEL_ITEM_DELETED, m_owner->GetId() );
+    event.SetEventObject( m_owner );
+    event.SetModel( m_owner->GetModel() );
+    event.SetItem( item );
+    m_owner->GetEventHandler()->ProcessEvent( event );
+
+    return true;
+}
+
+bool wxDataViewCtrlInternal::ItemChanged( const wxDataViewItem &item )
+{
+    wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_MODEL_ITEM_CHANGED, m_owner->GetId() );
+    event.SetEventObject( m_owner );
+    event.SetModel( m_owner->GetModel() );
+    event.SetItem( item );
+    m_owner->GetEventHandler()->ProcessEvent( event );
+    
+    return true;
+}
+
+bool wxDataViewCtrlInternal::ValueChanged( const wxDataViewItem &item, unsigned int col )
+{
+    wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_MODEL_VALUE_CHANGED, m_owner->GetId() );
+    event.SetEventObject( m_owner );
+    event.SetModel( m_owner->GetModel() );
+    event.SetColumn( col );
+    event.SetItem( item );
+    m_owner->GetEventHandler()->ProcessEvent( event );
+    
+    return true;
+}
+
+bool wxDataViewCtrlInternal::Cleared()
+{
+    wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_MODEL_CLEARED, m_owner->GetId() );
+    event.SetEventObject( m_owner );
+    event.SetModel( m_owner->GetModel() );
+    m_owner->GetEventHandler()->ProcessEvent( event );
+    
     return true;
 }