Click here to Skip to main content
16,020,628 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I am totally new in MVVM pattern. It is pretty complicated to understand. I think i learned how to change property/value using data binding and commands but i do not know how to save changes to database.

What I have tried:

This is my Entity class in model folder:
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));
            }
        }
    }

And this is my view model:
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();
                }
            }

        }
    }

And this is XAML window:
<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>

And in app.xaml.cs:
protected override void OnStartup(StartupEventArgs e)
{
using (var ctx=new BazaContext())
{
ctx.Database.Migrate();
}
base.OnStartup(e);
WpfApp1.View.Products products = new View.Products();
ViewModel.Pogled VM = new ViewModel.Pogled();
products.DataContext = VM;
products.Show();
}
I do not know where to call dbcontext.SaveChanges()
Posted
Updated 18-Feb-20 8:20am
Comments
AnkushK1 16-Feb-20 17:52pm    
Where is the BazaContext class resides and what is dbcontext here? looking at your code, i believe BazaContext should have an instance of dbcontext and has a SaveChanges() method and this is where your dbcontext.SaveChanges() would go
Gruja82 16-Feb-20 22:33pm    
BazaContext is dbcontext. I tried to call SaveChanges() in the Execute method of the command but nothing happens
[no name] 17-Feb-20 14:29pm    
Your "dbContext" needs to stay in "scope" while making "changes" and calling "save".

You're creating dbContexts, then basically doing nothing and then letting them go out of scope.

1 solution

As Gerry mentioned in the comments, you need to call SaveChanges on the same instance of your DbContext class that you used to load the entities you're editing.

You'll probably also want to use an ObservableCollection[^] instead of a List as the backing store for the items you're editing.

Simplistically:
C#
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();
        }
    }
}

You can simplify that by using a common DelegateCommand class to provide the ICommand implementation:
C#
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);
    }
}
With that class defined (you only need to do that once), your view model becomes simpler:
C#
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();
    }
}
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900