Unable to cast COM Object to class type

3

I am making a library management software. I have separated management of database to a separate c# library 'DataAccessLibrary'. It contains DataAccess.cs:

public static event MyDelegate Event_AddBook;

    public static void InitializeDatabase()
    {
        using (SqliteConnection db = new SqliteConnection("Filename=MyBooks.db"))
        {
            db.Open();

            //Not necessary
        }
    }

    public static void AddBook(Book book)
    {
        Event_AddBook.Invoke(book);

        using (SqliteConnection db = new SqliteConnection("Filename=MyBooks.db"))
        {
            db.Open();
            //Not necessary
        }            
    }

    public static ObservableCollection<Book> GetBooks()
    {
        ObservableCollection<Book> books = new ObservableCollection<Book>();

        using (SqliteConnection db = new SqliteConnection("Filename=MyBooks.db"))
        {
            db.Open();
            //Not necessary
        }

        return books;
    }
}

When a book is added to the database, it invokes the event so that my YourBooks_View class (which displays the books) is notified that a book is added.

(NOTE: The book is added using a new window.)

In some other file, I add a book to the database like this:

Book b = new Book
{
    Title = title,
    Author = author,
    Publisher = publisher,
    ISBN = isbn,
    Quantity = quantity.GetValueOrDefault(),
    CoverImageLocation = CoverImageUri
};

DataAccess.AddBook(b);

The event 'Event_AddBook' is subscribed to by YourBooks class:

public sealed partial class YourBooks_View : Page
{
    private BooksViewModel ViewModel { get; set; } = new BooksViewModel();

    public YourBooks_View()
    {
        this.InitializeComponent();
        DataAccess.Event_AddBook += new MyDelegate(this.GridView_AddBook);
    }

    private void GridView_AddBook(Book book)
    {
        ViewModel.Books.Add(book);
    }
}

The code compiles without errors but at run time, when I add the book, this exception is thrown at the line YourBooks_View.GridView_AddBook() :

System.InvalidCastException HResult=0x80004002 Message=Unable to cast COM object of type 'System.Collections.Specialized.NotifyCollectionChangedEventHandler' to class type 'System.Collections.Specialized.NotifyCollectionChangedEventHandler'. Instances of types that represent COM components cannot be cast to types that do not represent COM components; however they can be cast to interfaces as long as the underlying COM component supports QueryInterface calls for the IID of the interface. Source=System.Private.CoreLib StackTrace: at System.StubHelpers.StubHelpers.GetCOMIPFromRCW_WinRTDelegate(Object objSrc, IntPtr pCPCMD, IntPtr& ppTarget) at System.Collections.Specialized.NotifyCollectionChangedEventHandler.Invoke(Object sender, NotifyCollectionChangedEventArgs e) at System.Collections.ObjectModel.ObservableCollection1.OnCollectionChanged(NotifyCollectionChangedEventArgs e) at System.Collections.ObjectModel.ObservableCollection1.InsertItem(Int32 index, T item) at System.Collections.ObjectModel.Collection`1.Add(T item) at Bookshelf.YourBooks_View.GridView_AddBook(Book book) in C:\Users\Hemil\source\repos\Bookshelf\Bookshelf\YourBooks_View.xaml.cs:line 54 at DataAccessLibrary.DataAccess.AddBook(Book book) in C:\Users\Hemil\source\repos\Bookshelf\DataAccessLibrary\DataAccess.cs:line 44 at Bookshelf.NewBook_View.d__3.MoveNext() in C:\Users\Hemil\source\repos\Bookshelf\Bookshelf\NewBook_View.xaml.cs:line 137

I don't know what this means. Is there a way to solve this problem or is there a way to notify the view in some other way.

I am not so good in c#. Forgive me for any mistake or silly question.

EDIT: I am using Sqlite Database as provided in Microsoft.Data.Sqlite container.

EDIT: I followed this tutorial: https://docs.microsoft.com/en-us/windows/uwp/data-access/sqlite-databases. I am targetting the latest Windows 10 so I did not include Sqlite with my app

EDIT: I uploaded the whole source code to a public repository on gitlab here: https://gitlab.com/rahem027/bookshelf2

EDIT: I think i should have included BookViewModel source code as well. Well, here it is:

public class BooksViewModel
{
    private ObservableCollection<Book> books { get; set; }

    public ObservableCollection<Book> Books
    {
        get { return this.books; }

        set
        {
            this.books = value;
        }
    }


    public BooksViewModel()
    {
        books = DataAccess.GetBooks();
    }
}
c#
exception
uwp
com
runtimeexception
asked on Stack Overflow Sep 26, 2018 by Hemil • edited Sep 27, 2018 by Hemil

2 Answers

3

The reason you get this issue is that you update the Main View's ViewModel from the New View's thread. When you clicked the Add button, the AddBook event triggered, this is on the New View's thread, but you update the Main View's ViewModel in the YourBooks_View class. You should use the CoreDispatcher.RunAsync method to schedule work on the UI thread for the new view.

So just change your code of your GridView_AddBook method with CoreDispatcher.RunAsync method to schedule work on the UI thread to add new Book object.

Here is the modified code of GridView_AddBook method:

private async void GridView_AddBook(Book book)
{
    await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
    {
        ViewModel.Books.Add(book);
    });
}
answered on Stack Overflow Sep 27, 2018 by Breeze Liu - MSFT
0

the book object you are trying to add to the collection maybe attached to the database, When you perform an operation with the database make sure to Dispose its context ( that depends on which db provider you are using ).

So to work around that you can just try to copy the book object to a new instance and put that in your ViewModel Collection like so :

private void GridView_AddBook(Book book)
{
    Book b = new Book
    {
        Title = book.title,
        Author = book.author,
        Publisher = book.publisher,
        ISBN = book.isbn,
        Quantity = book.quantity.GetValueOrDefault(),
        CoverImageLocation = book.CoverImageUri
    };
    ViewModel.Books.Add(b);
}
answered on Stack Overflow Sep 26, 2018 by touseefbsb

User contributions licensed under CC BY-SA 3.0