Gruja82 Ответов: 1

CRUD операции в WPF MVVM с ядром EF


Я совершенно новичок в паттерне MVVM. Это довольно сложно понять. Я думаю, что узнал, как изменить свойство/значение с помощью привязки данных и команд, но я не знаю, как сохранить изменения в базе данных.

Что я уже пробовал:

Это мой класс сущностей в папке модели:
public class Proizvodi:INotifyPropertyChanged
    {
        private int id;
        private string sifra;
        private string naziv;
        private string jedmere;
        private int kolicina;
        private double cena;

        [Key]
        public int Id
        {
            get
            {
                return id;
            }
            set
            {
                id = value;
                OnPropertyChanged("Id");
            }
        }

        public string Sifra
        {
            get
            {
                return sifra;
            }
            set
            {
                sifra = value;
                OnPropertyChanged("Sifra");
            }
        }

        public string Naziv
        {
            get
            {
                return naziv;
            }
            set
            {
                naziv = value;
                OnPropertyChanged("Naziv");
            }
        }

        public string JedMere
        {
            get
            {
                return jedmere;
            }
            set
            {
                jedmere = value;
                OnPropertyChanged("JedMere");
            }
        }

        public int Kolicina
        {
            get
            {
                return kolicina;
            }
            set
            {
                kolicina = value;
                OnPropertyChanged("Kolicina");
            }
        }

        public double Cena
        {
            get
            {
                return cena;
            }
            set
            {
                cena = value;
                OnPropertyChanged("Cena");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        
        private void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged!=null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

И это моя точка зрения модель:
class Pogled
    {
        private List<Model.Proizvodi> sviProizvodi;
        
        public Pogled()
        {
            sviProizvodi = new List<Model.Proizvodi>();
            using (var ctx=new Model.BazaContext())
            {
                sviProizvodi = ctx.Proizvodi.ToList();
            }
        }

        public List<Model.Proizvodi> Proizvodis
        {
            get { return sviProizvodi; }
            set { sviProizvodi = value; }
        }

        private ICommand mUpdater;
        public ICommand UpdateCommand
        {
            get
            {
                if (mUpdater == null)
                    mUpdater = new Updater();
                return mUpdater;
            }
            set
            {
                mUpdater = value;
            }
        }

        private class Updater:ICommand
        {
            public bool CanExecute(object parameter)
            {
                return true;
            }

            public event EventHandler CanExecuteChanged;
            

            public void Execute(object parameter)
            {
                using (var ctx=new Model.BazaContext())
                {
                    ctx.SaveChanges();
                }
            }

        }
    }

А это окно XAML:
<Window x:Class="WpfApp1.View.Products"
        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:WpfApp1.View"
        mc:Ignorable="d"
        Title="Products" SizeToContent="WidthAndHeight">
    <Grid>
        <StackPanel Orientation="Vertical" Grid.ColumnSpan="2">
            <Border BorderThickness="0">
                <Label Content="Products" HorizontalAlignment="Center" FontSize="20"/>
            </Border>
            <StackPanel Orientation="Horizontal">
                <StackPanel x:Name="stackPanel" Orientation="Vertical">
                    <StackPanel x:Name="stackPanel1" Orientation="Horizontal">
                        <Label Content="Search"/>
                        <TextBox x:Name="textBoxSearch" MinWidth="120" MaxWidth="300"/>
                    </StackPanel>
                    <DataGrid x:Name="grdProizvodi" IsReadOnly="True" AutoGenerateColumns="False" Margin="0,10,0,0" ItemsSource="{Binding Proizvodis}">
                        <DataGrid.Columns>
                            <DataGridTextColumn Binding="{Binding Id}" Visibility="Hidden"/>
                            <DataGridTextColumn Binding="{Binding Sifra}" Header="Serial" MinWidth="100" MaxWidth="120">
                                <DataGridTextColumn.HeaderStyle>
                                    <Style TargetType="DataGridColumnHeader">
                                        <Setter Property="HorizontalContentAlignment" Value="Center"/>
                                    </Style>
                                </DataGridTextColumn.HeaderStyle>
                            </DataGridTextColumn>
                            <DataGridTextColumn Binding="{Binding Naziv}" Header="Name" MinWidth="150" MaxWidth="300">
                                <DataGridTextColumn.HeaderStyle>
                                    <Style TargetType="DataGridColumnHeader">
                                        <Setter Property="HorizontalContentAlignment" Value="Center"/>
                                    </Style>
                                </DataGridTextColumn.HeaderStyle>
                            </DataGridTextColumn>
                            <DataGridTextColumn Binding="{Binding JedMere}" Header="Unit" MinWidth="100" MaxWidth="120">
                                <DataGridTextColumn.HeaderStyle>
                                    <Style TargetType="DataGridColumnHeader">
                                        <Setter Property="HorizontalContentAlignment" Value="Center"/>
                                    </Style>
                                </DataGridTextColumn.HeaderStyle>
                            </DataGridTextColumn>
                            <DataGridTextColumn Binding="{Binding Kolicina}" Header="QTY" MinWidth="100" MaxWidth="120">
                                <DataGridTextColumn.HeaderStyle>
                                    <Style TargetType="DataGridColumnHeader">
                                        <Setter Property="HorizontalContentAlignment" Value="Center"/>
                                    </Style>
                                </DataGridTextColumn.HeaderStyle>
                            </DataGridTextColumn>
                            <DataGridTextColumn Binding="{Binding Cena}" Header="Price" MinWidth="100" MaxWidth="120">
                                <DataGridTextColumn.HeaderStyle>
                                    <Style TargetType="DataGridColumnHeader">
                                        <Setter Property="HorizontalContentAlignment" Value="Center"/>
                                    </Style>
                                </DataGridTextColumn.HeaderStyle>
                            </DataGridTextColumn>
                            
                        </DataGrid.Columns>
                    </DataGrid>

                </StackPanel>
                <Line Y2="{Binding ActualHeight, ElementName=stackPanel2, Mode=OneWay}" StrokeThickness="5" Stroke="Blue"/>
                <StackPanel x:Name="stackPanel2" Orientation="Vertical">
                    <Label Content="Details" FontSize="16" HorizontalAlignment="Center"/>
                    <StackPanel Orientation="Horizontal" Margin="0,10,0,0">
                        <Label Content="ID"/>
                        <TextBox x:Name="textBoxId" IsReadOnly="True" MinWidth="100" MaxWidth="120" Text="{Binding ElementName=grdProizvodi, Path=SelectedItem.Id}"/>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal" Margin="0,10,0,0">
                        <Label Content="Serial"/>
                        <TextBox x:Name="textBoxSifra" MinWidth="100" MaxWidth="120" Text="{Binding ElementName=grdProizvodi, Path=SelectedItem.Sifra}"/>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal" Margin="0,10,0,0">
                        <Label Content="Name"/>
                        <TextBox x:Name="textBoxNaziv" MinWidth="150" MaxWidth="300" Text="{Binding ElementName=grdProizvodi, Path=SelectedItem.Naziv}"/>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal" Margin="0,10,0,0">
                        <Label Content="Unit"/>
                        <TextBox x:Name="textBoxJedMere" MinWidth="100" MaxWidth="120" Text="{Binding ElementName=grdProizvodi, Path=SelectedItem.JedMere}"/>
                        <Button x:Name="buttonJedMere" Content="New Unit"/>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal" Margin="0,10,0,0">
                        <Label Content="QTY"/>
                        <TextBox x:Name="textBoxKolicina" MinWidth="100" MaxWidth="120" IsReadOnly="True" Text="{Binding ElementName=grdProizvodi, Path=SelectedItem.Kolicina}"/>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal" Margin="0,10,0,0">
                        <Label Content="Price"/>
                        <TextBox x:Name="textBoxCena" MinWidth="100" MaxWidth="120" Text="{Binding ElementName=grdProizvodi, Path=SelectedItem.Cena}"/>
                    </StackPanel>
                    <Border BorderBrush="Red" BorderThickness="1" Margin="0,10,0,0">
                        <StackPanel Orientation="Vertical" Margin="0,0,10,0">
                            <Label Content="Material" HorizontalAlignment="Center"/>
                            <DataGrid x:Name="grdMaterijal" MaxHeight="150" IsReadOnly="True">
                                <DataGrid.Columns>
                                    <DataGridTextColumn Binding="{Binding Key}" Visibility="Hidden"/>
                                    <DataGridTextColumn Binding="{Binding Value.Sifra}" Header="Serial" MinWidth="100" MaxWidth="100">
                                        <DataGridTextColumn.HeaderStyle>
                                            <Style TargetType="DataGridColumnHeader">
                                                <Setter Property="HorizontalContentAlignment" Value="Center"/>
                                            </Style>
                                        </DataGridTextColumn.HeaderStyle>
                                    </DataGridTextColumn>
                                    <DataGridTextColumn Binding="{Binding Value.Naziv}" Header="Name" MinWidth="100" MaxWidth="200">
                                        <DataGridTextColumn.HeaderStyle>
                                            <Style TargetType="DataGridColumnHeader">
                                                <Setter Property="HorizontalContentAlignment" Value="Center"/>
                                            </Style>
                                        </DataGridTextColumn.HeaderStyle>
                                    </DataGridTextColumn>
                                    <DataGridTextColumn Binding="{Binding Value.JedMere}" Header="Unit" MinWidth="100" MaxWidth="100">
                                        <DataGridTextColumn.HeaderStyle>
                                            <Style TargetType="DataGridColumnHeader">
                                                <Setter Property="HorizontalContentAlignment" Value="Center"/>
                                            </Style>
                                        </DataGridTextColumn.HeaderStyle>
                                    </DataGridTextColumn>
                                    <DataGridTextColumn Binding="{Binding Value.Kolicina}" Header="QTY" MinWidth="100" MaxWidth="100">
                                        <DataGridTextColumn.HeaderStyle>
                                            <Style TargetType="DataGridColumnHeader">
                                                <Setter Property="HorizontalContentAlignment" Value="Center"/>
                                            </Style>
                                        </DataGridTextColumn.HeaderStyle>
                                    </DataGridTextColumn>
                                </DataGrid.Columns>
                            </DataGrid>
                            <Button x:Name="buttonIzmeni" Content="Change" MaxWidth="100" Margin="0,10,0,0"/>
                            <StackPanel Orientation="Horizontal" Margin="0,10,0,10">
                                <Label Content="Prod. Price"/>
                                <TextBox x:Name="textBoxCenaProizvodnje" MinWidth="120" MaxWidth="150" IsReadOnly="True"/>
                            </StackPanel>
                        </StackPanel>
                    </Border>
                    <Label Content="Image" HorizontalAlignment="Center" Margin="0,10,0,0"/>
                    <Border BorderBrush="Black" BorderThickness="1"  MaxHeight="150" MaxWidth="150" >
                        <Image x:Name="img" HorizontalAlignment="Left" VerticalAlignment="Top"  Stretch="Fill" Width="150" Height="150"  Margin="0"/>
                    </Border>
                    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="0,5,0,0">
                        <Button x:Name="buttonUvoz" Content="Import"/>
                        <Button x:Name="buttonObrisiSliku" Content="Delete" Margin="40,0,0,0"/>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal" Margin="0,10,0,10" HorizontalAlignment="Center">
                        <Button x:Name="buttonNovi" Content="New"/>
                        <Button x:Name="buttonObrisi" Content="Delete" Margin="50,0,0,0"/>
                        <Button x:Name="buttonPotvrdi" Content="Confirm" Margin="50,0,0,0" Command="{Binding Path=UpdateCommand}" Click="buttonPotvrdi_Click"/>
                    </StackPanel>
                    <DataGrid x:Name="test" AutoGenerateColumns="True"/>
                </StackPanel>
            </StackPanel>
        </StackPanel>
    </Grid>
</Window>

И в приложение.язык XAML.в CS:
охраняемых переопределить недействительными OnStartup(StartupEventArgs е)
{
использование (var ctx=new BazaContext())
{
ctx.база данных.Мигрировать();
}
база.OnStartup(e);
WpfApp1.View.Продукты продукты = новый вид.Продукты();
модель представления.Pogled VM = новая модель представления.Поглед();
продукты.DataContext = виртуальная машина;
продукты.Покажите();
}
Я не знаю, где вызвать dbcontext.SaveChanges()

AnkushK1

Где находится класс BazaContext и что такое dbcontext здесь? глядя на ваш код, я считаю, что BazaContext должен иметь экземпляр dbcontext и иметь метод SaveChanges (), и именно туда пойдет ваш dbcontext.SaveChanges()

Gruja82

BazaContext - это dbcontext. Я попытался вызвать SaveChanges() в методе Execute команды, но ничего не произошло

Gerry Schmitz

Ваш "dbContext" должен оставаться в "области видимости", внося "изменения" и вызывая "сохранить".

Вы создаете dbContexts, затем в основном ничего не делаете, а затем позволяете им выйти за пределы области действия.

1 Ответов

Рейтинг:
2

Richard Deeming

Как Джерри упомянул в комментариях, вам нужно позвонить SaveChanges на том же самом экземпляре вашего DbContext класс, который вы использовали для загрузки редактируемых сущностей.

Вы, вероятно, также захотите использовать ObservableCollection[^] вместо a List в качестве резервного хранилища для элементов, которые вы редактируете.

Упрощенно:

class Pogled : IDisposable
{
    private readonly Model.BazaContext context;
    private readonly ObservableCollection<Model.Proizvodi> sviProizvodi;
    private readonly ICommand mUpdater;
    
    public Pogled()
    {
        context = new Model.BazaContext();
        sviProizvodi = new ObservableCollection<Model.Proizvodi>(context.Proizvodi);
        mUpdater = new Updater(this);
    }

    public ObservableCollection<Model.Proizvodi> Proizvodis
    {
        get { return sviProizvodi; }
    }

    public ICommand UpdateCommand
    {
        get { return mUpdater; }
    }
    
    public void Dispose()
    {
        context.Dispose();
    }

    private class Updater : ICommand
    {
        private readonly Pogled mOwner;
        
        public Updater(Pogled owner)
        {
            mOwner = owner;
        }
        
        public bool CanExecute(object parameter)
        {
            return true;
        }

        public event EventHandler CanExecuteChanged;
            
        public void Execute(object parameter)
        {
            mOwner.context.SaveChanges();
        }
    }
}

Вы можете упростить это, используя общий DelegateCommand класс для обеспечения ICommand реализация:
public sealed class DelegateCommand : ICommand
{
    private readonly Action<object> _execute;
    private readonly Func<object, bool> _canExecute;
    
    public DelegateCommand(Action<object> execute, Func<object, bool> canExecute)
    {
        _execute = execute;
        _canExecute = canExecute;
    }
    
    public DelegateCommand(Action<object> execute) : this(execute, _ => true)
    {
    }
    
    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }
    
    public bool CanExecute(object parameter)
    {
        return _canExecute(parameter);
    }
    
    public void Execute(object parameter)
    {
        _execute(parameter);
    }
}
С этим классом, определенным (вам нужно сделать это только один раз), ваша модель представления становится проще:
class Pogled : IDisposable
{
    private readonly Model.BazaContext context;
    private readonly ObservableCollection<Model.Proizvodi> sviProizvodi;
    private readonly ICommand mUpdater;
    
    public Pogled()
    {
        context = new Model.BazaContext();
        sviProizvodi = new ObservableCollection<Model.Proizvodi>(context.Proizvodi);
        mUpdater = new DelegateCommand(_ => Update());
    }

    public ObservableCollection<Model.Proizvodi> Proizvodis
    {
        get { return sviProizvodi; }
    }

    public ICommand UpdateCommand
    {
        get { return mUpdater; }
    }
    
    public void Dispose()
    {
        context.Dispose();
    }
    
    private void Update()
    {
        context.SaveChanges();
    }
}