WPF Rilegatura automatica quando i valori di un'entità EF cambiano

c# data-binding entity-framework entity-framework-core wpf

Domanda

Sono nuovo in Entity Framework e sto cercando di impararlo.

Stavo cercando di modificare un esercizio trovato nella documentazione ufficiale: mi piacerebbe avere un elenco di padri e un elenco di figli. Ogni figlio deve avere un padre selezionato da un menu della casella combinata.

Ora posso farlo ma, se aggiungo un padre, non lo vedo nella lista padre né nella casella combinata. Se aggiungo un figlio, non vedo il figlio nell'elenco dei figli.

Se chiudo e riapro il programma, vedo correttamente padri e figli aggiunti in precedenza.

Come posso aggiornare automaticamente i dati in combobox e listview?

Non mi piace chiamare una funzione da aggiornare, vorrei effettuare automaticamente l'aggiornamento quando si modifica qualcosa nel database.

Il mio progetto è composto da 3 file:

MainWindow.xaml

<Window x:Class="EF7Fam.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:EF7Fam"
        mc:Ignorable="d"
        Loaded="Page_Loaded"
        Title="MainWindow" Height="350" Width="550">

    <Grid>
        <StackPanel Orientation="Horizontal">
            <StackPanel Width="263" Margin="3 0 3 0">
                <TextBox Name="NewFT"></TextBox>
                <Button Click="Add_Click">Add</Button>
                <ListView Name="Fathers">
                    <ListView.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" />
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>
            </StackPanel>
            <StackPanel Width="263" Margin="3 0 3 0">
                <TextBox Name="NewSN"></TextBox>
                <ComboBox Name="FT" DisplayMemberPath="Name" SelectedValuePath="FTId"/>
                <Button Click="Add_SN_Click">Add</Button>
                <ListView Name="Sons">
                    <ListView.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" />
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>
            </StackPanel>
        </StackPanel>
    </Grid>
</Window>

MainWindow.xaml.cs

using Microsoft.Data.Entity;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace EF7Fam
{
    /// <summary>
    /// Logica di interazione per MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            using (var db = new Family())
            {
                db.Database.Migrate();
            }
        }

        private void Page_Loaded(object sender, RoutedEventArgs e)
        {
            using (var db = new Family())
            {
                Fathers.ItemsSource = db.Fathers.ToList();
                Sons.ItemsSource = db.Sons.ToList();
                FT.ItemsSource = db.Fathers.ToList();
            }
        }

        private void Add_Click(object sender, RoutedEventArgs e)
        {
            using (var db = new Family())
            {
                var ft = new Father { Name = NewFT.Text };
                db.Fathers.Add(ft);
                db.SaveChanges();
            }
        }

        private void Add_SN_Click(object sender, RoutedEventArgs e) 
        {
            using (var db = new Family())
            {
                var sn = new Son { Name = NewSN.Text, FTId = Int32.Parse(FT.SelectedValue.ToString()) };
                db.Sons.Add(sn);
                db.SaveChanges();
            }
        }
    }
}

Model.cs

using System;
using Microsoft.Data.Entity;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Runtime.CompilerServices;

namespace EF7Fam
{

    public class Family : DbContext
    {
        public DbSet<Father> Fathers { get; set; }
        public DbSet<Son> Sons { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlite($"Filename=Family.db");
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Father>()
                .Property(b => b.Name)
                .IsRequired();
        }
    }

    public class Father : INotifyPropertyChanged
    {
        [Key]
        public int FTId { get; set; }
        public string Name { get; set; }

        public List<Son> Sons { get; set; }

        public event PropertyChangedEventHandler PropertyChanged;

        public void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }


    public class Son : INotifyPropertyChanged
    {
        [Key]
        public int SNId { get; set; }
        public string Name { get; set; }

        public int FTId { get; set; }
        public Father Father { get; set; }

        public event PropertyChangedEventHandler PropertyChanged;

        public void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Ho guardato molte volte su questo sito e sul Web, ma senza trovare una soluzione.

Sarò molto grato se qualcuno mi può aiutare a farmi sapere cosa sto facendo male,

Grazie CIAO,

Enrico

Risposta popolare

Per DbSets i tuoi controlli ai DbSets devi fare questo:

private void Page_Loaded(object sender, RoutedEventArgs e)
{
        using (var db = new Family())
        {
            db.Fathers.Load();
            Fathers.ItemsSource = db.Fathers.Local;
            db.Sons.Load();
            Sons.ItemsSource = db.Sons.Local;
            FT.ItemsSource = db.Fathers.Local;
        }
}

Chiamando il metodo Load si caricheranno gli oggetti esistenti nella memoria e la proprietà DbSet<TEntity>.Local fornirà una ObservableCollection<TEntity> che contiene tutti gli oggetti Unchanged , Modified e Added attualmente tracciati da DbContext per il DbSet . L'aggiunta o la rimozione da ObservableCollection eseguirà anche l' Add / Remove corrispondente sul DbSet .

In questo modo se hai bisogno di salvare le modifiche dopo aver eseguito tutte le operazioni necessarie nella tua vista, puoi definire un comando o annullare l'evento click di un pulsante nella tua vista e chiamare il metodo SaveChanges del tuo contesto:

  private void SaveChanges_Click(object sender, RoutedEventArgs e) 
  {
        using (var db = new Family())
        {
            db.SaveChanges();
        }
  }

Aggiornare

Ora ho visto che stai usando EF7, beh, il vero è che non sono a conoscenza di tutte le modifiche in questa versione, ma posso dirti che ce ne sono molte, forse questa proprietà non è ancora implementata. Ho trovato una domanda in merito e non ho ancora ricevuto risposta.

Scavando di più nella documentazione, penso di aver trovato una soluzione, ma il vero è che non mi piace, ma potrebbe funzionare finché non viene visualizzata la proprietà Load . Secondo la documentazione EF puoi fare questo:

private void Add_Click(object sender, RoutedEventArgs e)
{
        using (var db = new Family())
        {
            var ft = new Father { Name = NewFT.Text };
            db.Fathers.Add(ft);
            db.SaveChanges();
            Fathers.ItemsSource = db.Fathers.ToList();
        }
 }

Se trovo una soluzione migliore ti farò sapere.




Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché