Вопрос или проблема
У меня есть небольшое приложение WPF / .NET, соединенное с базой данных SQLite через System.Data.Entity
. В MainWindow
есть кнопка и текстовое поле. Когда кнопка нажата, новый элемент с id должен быть добавлен в базу данных. Это работает и обновляет dataGrid правильно. Но если элемент с текущим id уже существует, вместо этого должно увеличиваться значение count. Эти изменения правильно применяются к базе данных, но не к data grid. Значение в dataGrid обновляется только тогда, когда я прокручиваю вниз, пока он не скрывается, а затем снова появляются. Как я могу это правильно исправить?
Код MainWindow.xaml.cs
выглядит следующим образом:
public partial class MainWindow : Window
{
private ProductContext _context;
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Product newProduct = new Product() {
Id = idTextBox.Text,
Count = 1
};
Product oldProduct = _context.Products.Find(newProduct.Id);
if(oldProduct!= null)
oldProduct.Count++;
else
_context.Products.Add(newProduct);
_context.SaveChanges();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
_context = new ProductContext();
_context.Products.Load();
dataGrid.ItemsSource = _context.Products.Local;
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
_input.Dispose();
}
}
Код DataGrid в MainWindow.xaml
:
<DataGrid AutoGenerateColumns="False" Name="dataGrid">
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="{Binding Id}"/>
<DataGridTextColumn Header="COUNT" Binding="{Binding Count}"/>
</DataGrid.Columns>
</DataGrid>
Контекст базы данных:
public partial class ProductContext : DbContext
{
public DbSet<Product> Products { get; set; }
public ProductContext () : base("name=ProductDB") { }
}
Продукт:
public class Product
{
public string Id { get; set; }
public int Count { get; set; }
}
Я пробовал добавлять _context.Products.Load() и несколько других неудачных вариантов, но ничего не изменилось.
П.С. Я буду очень признателен за совет, если я принципиально делаю что-то неправильно при взаимодействии с базой данных
Ответ или решение
Чтобы ваш WPF DataGrid корректно обновлялся после изменения значений в вашей базе данных, вам необходимо убедиться, что изменения, примененные к объектам в контексте Entity Framework, извлекаются и отражаются в привязанном источнике данных. В вашем случае, проблема заключается в том, что DataGrid не обновляется автоматически, когда учётные записи уже существуют и вы увеличиваете значение поля Count
.
Проблема, с которой вы столкнулись, связана с тем, что ObservableCollection
или аналогичная структура данных может лучше поддерживать уведомления об изменениях. Давайте рассмотрим, как можно это исправить.
Решение
-
Используйте
ObservableCollection
:
Замените локальную коллекцию наObservableCollection
. Это обеспечит, что любые изменения будут автоматически отражаться в DataGrid. -
Используйте интерфейс
INotifyPropertyChanged
:
Убедитесь, что ваш классProduct
реализуетINotifyPropertyChanged
, чтобы обеспечить уведомления об изменении свойств.
Вот обновлённый код вашего класса Product
и изменённый код в MainWindow.xaml.cs
.
Класс Product
using System.ComponentModel;
public class Product : INotifyPropertyChanged
{
private string _id;
private int _count;
public string Id
{
get => _id;
set
{
_id = value;
OnPropertyChanged(nameof(Id));
}
}
public int Count
{
get => _count;
set
{
_count = value;
OnPropertyChanged(nameof(Count));
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Класс MainWindow
using System.Collections.ObjectModel;
using System.Data.Entity;
using System.Windows;
public partial class MainWindow : Window
{
private ProductContext _context;
private ObservableCollection<Product> _products;
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
string productId = idTextBox.Text;
Product oldProduct = _context.Products.Find(productId);
if (oldProduct != null)
{
oldProduct.Count++;
// Вызовите метод для уведомления об изменениях
_context.Entry(oldProduct).State = EntityState.Modified;
}
else
{
Product newProduct = new Product()
{
Id = productId,
Count = 1
};
_context.Products.Add(newProduct);
_products.Add(newProduct); // добавляем в ObservableCollection
}
_context.SaveChanges();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
_context = new ProductContext();
_products = new ObservableCollection<Product>(_context.Products.Local.ToList());
dataGrid.ItemsSource = _products;
_context.Products.Load(); // Загружаем данные из базы данных
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
_context.Dispose();
}
}
Объяснение изменений:
-
ObservableCollection: Вместо того, чтобы использовать
Local
, мы создаем новую экземплярObservableCollection
и привязываем его к DataGrid. Это позволяет автоматически обновлять интерфейс при изменении коллекции. -
INotifyPropertyChanged: Реализация интерфейса
INotifyPropertyChanged
в вашем классеProduct
позволяет уведомлять интерфейс о том, что свойство изменилось, что приводит к его автоматическому обновлению в DataGrid. -
Изменение состояния: При увеличении значения
Count
, мы явно изменяем состояние записи в Entity Framework, чтобы оно сталоModified
. Это гарантирует, что изменения будут отслеживаться правильным образом.
Теперь, когда вы обновляете существующий элемент в базе данных, данные в DataGrid будут обновляться корректно и без необходимости прокручивать и скрывать строки.
Попробуйте внести указанные изменения, и ваша проблема должна быть решена.