Я делаю программное обеспечение для управления библиотекой. Я разделил управление базой данных на отдельную библиотеку С# DataAccessLibrary. Он содержит 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;
}
}
Когда книга добавляется в базу данных, она вызывает событие, так что мой класс MyBooks_View (который отображает книги) уведомляется о том, что книга добавлена.
(ПРИМЕЧАНИЕ. Книга добавляется в новом окне.)
В другом файле я добавляю книгу в базу данных следующим образом:
Book b = new Book
{
Title = title,
Author = author,
Publisher = publisher,
ISBN = isbn,
Quantity = quantity.GetValueOrDefault(),
CoverImageLocation = CoverImageUri
};
DataAccess.AddBook(b);
Событие "Event_AddBook" подписывается классом YourBooks:
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);
}
}
Код компилируется без ошибок, но во время выполнения, когда я добавляю книгу, это исключение вызывается в строке YourBooks_View.GridView_AddBook():
System.InvalidCastException HResult = 0x80004002 Сообщение = Невозможно передать COM-объект типа "System.Collections.Specialized.NotifyCollectionChangedEventHandler" в тип класса "System.Collections.Specialized.NotifyCollectionChangedEventHandler". Экземпляры типов, представляющих COM-компоненты, нельзя отбрасывать типам, которые не представляют COM-компоненты; однако они могут быть переданы в интерфейсы до тех пор, пока базовый COM-компонент поддерживает вызовы QueryInterface для IID интерфейса. Source = System.Private.CoreLib StackTrace: at System.StubHelpers.StubHelpers.GetCOMIPFromRCW_WinRTDelegate (Object objSrc, IntPtr pCPCMD, IntPtr & ppTarget) в System.Collections.Specialized.NotifyCollectionChangedEventHandler.Invoke(Object sender, NotifyCollectionChangedEventArgs e) в System.Collections.ObjectModel.ObservableCollection
1.OnCollectionChanged(NotifyCollectionChangedEventArgs e) at System.Collections.ObjectModel.ObservableCollection
1.InsertItem (индекс Int32, элемент T) в System.Collections.ObjectModel.Collection'1.Add (элемент T) в Bookshelf.YourBooks_View.GridView_AddBook ( Book book) в C:\Users\Hemil\source\repos\Bookshelf\Bookshelf\YourBooks_View.xaml.cs: строка 54 в DataAccessLibrary.DataAccess.AddBook (книга) в C:\Users\Hemil\source\repos\Bookshelf\DataAccessLibrary\DataAccess.cs: строка 44 в Bookshelf.NewBook_View.d__3.MoveNext() в C:\Users\Hemil\source\repos\Bookshelf\Bookshelf\NewBook_View.xaml.cs: строка 137
Я не знаю, что это значит. Есть ли способ решить эту проблему или есть способ уведомить мнение каким-то другим способом.
Я не так хорош в С#. Прости меня за любую ошибку или глупый вопрос.
EDIT: Я использую базу данных Sqlite, как показано в контейнере Microsoft.Data.Sqlite.
EDIT: Я следовал этому руководству: https://docs.microsoft.com/en-us/windows/uwp/data-access/sqlite-databases. Я нацелен на последнюю версию Windows 10, поэтому я не включил Sqlite с моим приложением
EDIT: я загрузил весь исходный код в общедоступный репозиторий на gitlab: https://gitlab.com/rahem027/bookshelf2
EDIT: Я думаю, что я должен был включить исходный код BookViewModel. Ну вот, вот:
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();
}
}
Причина, по которой возникает эта проблема, заключается в том, что вы обновляете Main View ViewModel
из потока New View. Когда вы нажмете кнопку " Add
, событие " AddBook
, это будет в потоке "Новый вид", но вы обновите Main View ViewModel
в классе YourBooks_View
. Вы должны использовать метод CoreDispatcher.RunAsync, чтобы запланировать работу над потоком пользовательского интерфейса для нового представления.
Поэтому просто измените свой код вашего метода GridView_AddBook
с помощью метода CoreDispatcher.RunAsync, чтобы запланировать работу над потоком пользовательского интерфейса, чтобы добавить новый объект Book
.
Вот модифицированный код метода GridView_AddBook
:
private async void GridView_AddBook(Book book)
{
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
ViewModel.Books.Add(book);
});
}
объект книги, который вы пытаетесь добавить в коллекцию, может быть привязан к базе данных. Когда вы выполняете операцию с базой данных, обязательно удаляйте ее контекст (который зависит от того, какой поставщик db вы используете).
Поэтому, чтобы обойти это, вы можете просто попытаться скопировать объект книги в новый экземпляр и поместить его в свою коллекцию ViewModel так:
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);
}