WPF EF의 엔터티 값이 변경되면 자동 바인딩

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

문제

Entity Framework를 처음 사용하고 있으며이를 배우려고합니다.

나는 공식 문서에서 발견 된 운동을 수정하려고 노력했다 : 나는 아버지의 목록과 아들의 목록을 갖고 싶다. 모든 아들은 콤보 박스 메뉴에서 선택된 아버지를 가져야합니다.

이제는 할 수 있지만 아버지를 추가하면 아버지 목록이나 콤보 박스에서 볼 수 없습니다. 아들을 추가하면 나는 아들의 목록에 아들을 보지 못합니다.

프로그램을 닫고 다시 열면 이전에 추가 된 아버지와 아들을 올바르게 볼 수 있습니다.

콤보 박스 및리스트 뷰에서 데이터를 자동으로 업그레이드하는 방법은 무엇입니까?

내가 새로 고치려면 함수를 호출하고 싶지 않아, 자동으로 데이터베이스에서 무언가를 바꿀 때 새로 고침하고 싶습니다.

내 프로젝트는 3 개의 파일로 구성됩니다.

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));
        }
    }
}

나는이 사이트와 웹에서 여러 번 보였지만 해결책을 찾지 못했습니다.

나는 누군가 내가 나에게 내가 뭘 잘못하고 있는지 알려주도록 도울 수 있다면 매우 감사 할 것이다.

고마워, 안녕,

엔리코

인기 답변

컨트롤을 DbSets 바인딩하려면 다음 작업을 수행해야합니다.

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;
        }
}

Load 메서드를 호출하면 기존 개체를 메모리에로드하고 DbSet<TEntity>.Local 속성을 사용하면 지정된 DbSetDbContext 에서 현재 추적중인 Unchanged , ModifiedAdded 개체가 모두 포함 된 ObservableCollection<TEntity>DbSet 있습니다. ObservableCollection 에서 추가 또는 제거하면 DbSet 의 해당 Add / Remove 도 수행됩니다.

이렇게하면보기에 필요한 모든 작업을 수행 한 후에 변경 사항을 저장해야하는 경우 명령을 정의하거나보기에서 단추의 클릭 이벤트를 무시하고 컨텍스트의 SaveChanges 메서드를 호출 할 수 있습니다.

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

최신 정보

이제는 EF7을 사용하고있는 것을 보았습니다. 사실이 버전의 모든 변경 사항에 대해서는 알지 못하고 있지만, 많은 부분이 있다고 말할 수 있습니다.이 속성은 아직 구현되지 않았습니다. 나는 그것에 대해 묻는 질문을 발견하고 아직 대답하지 않습니다.

문서에서 더 많이 파고 나는 해결책을 찾았지만 사실은 좋지 않지만 Load 속성이 나타날 때까지 작동 할 수 있습니다. EF 문서에 따르면 다음과 같이 할 수 있습니다.

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();
        }
 }

더 나은 해결책을 찾으면 알려 드리겠습니다.




아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.
아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.