1

I have one action in my view model to add record in to entity frame work.I have one action to display the records in the view like this :

    private void FillProspects()

    {
        var q = (from a in ctx2.Prospects// 'ctx' is the object of entity 
                 select a).ToList();
        this.Prospects = q;               // 'Porspects' is a collection of   entity class this I have bound with my List view in my view
    }

This will be called in construction of my view model.as a result the list view in my view will be showing the records . I have one add record action in my view model..I have created properties in my view model corresponding to properties generated in the entity class for example:

      private String _FirstName;
      public String FirstName
      {
         get
        {
             return _FirstName;
        }
        set
        {
            _FirstName = value;

        }
     }

And my add record action in the view model is :

    public void Add1()
    {
        newprospect = new Prospect();
        newprospect.ID = Guid.NewGuid();
        newprospect.FirstName = FirstName;
        newprospect.LastName = LastName;
        newprospect.Address = Address;
        newprospect.State = State;
        newprospect.City = City;
        newprospect.ZIP = ZIP;
        prospect = newprospect;
        ctx2.AddToProspects(prospect);
        FillProspects();
        //RaisePropertyChanged("Prospects");
    }

I have inherited the : INotifyPropertyChanged and imported it's

using System.Windows.Input; 
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private void RaisePropertyChanged(string property) { PropertyChanged(this, new PropertyChangedEventArgs(property)); }

But my notification is not refreshing my view Listview records after adding record .so I just call the fill records method 'FillProspects' in the addrecord action..Is this right way of doing MVVM .Why my Listview is not getting refreshed after add record action where I am missing?I have tried with RaisePropertyChanged("Prospects");in the Add record action...but it is not refreshing .So I just called fill method action again

My complete view model:

           using System;
       using System.Collections.Generic;
       using System.Linq;
     using System.Text;
      using System.ComponentModel;
     using System.Windows.Input;
     using System.Collections.ObjectModel;

     namespace Wpfentity3
  {
public class frmProspects_VM : INotifyPropertyChanged
{
    TestsEntities ctx2 = new TestsEntities();
    public ObservableCollection<Prospect> prospects { get; set; }
    //This is the collection where records - er, entities - returned by a query are stored; 
    //Prospect is the generated class that defines a record - er,
    //an entity as well as the query for that table.

    private CommandMap _Commands;
    public CommandMap Commands { get { return _Commands; } }   

    Prospect newprospect;
    //This holds a new prospect that is created and then added to the prospects collection
    private Prospect _prospect;
    public Prospect prospect {
                                 get
                                 { 
                                     return _prospect;
                                 } 
                                 set 
                                 { 
                                     _prospect = value;
                                     RaisePropertyChanged("prospect");
                                 }
                              }

    //prospect is the object that holds the current record from the Prospects table.
    //MainWindow  controls are bound to this object


    public frmProspects_VM()
    {
        //FillProspects();
        ctx2 = new TestsEntities();
        //This instantiates the EntityManager class  ;
        prospects = new ObservableCollection<Prospect>();
        //This instantiates the prospects collection of Prospect records - er, entities;

        _Commands = new CommandMap();
        _Commands.AddCommand("Add", x => Add1());
    }

    private ObservableCollection<Prospect> _prospects;
    public ObservableCollection<Prospect> Prospects
   {
      get
      {
        return _prospects;
      }
      set
     {
        _prospects = value;
        RaisePropertyChanged("Prospects");
      }
  }

    private String _FirstName;
    public String FirstName
    {
        get
        {
            return _FirstName;
        }
        set
        {
            _FirstName = value;

        }
    }
    private String _LastName;
    public String LastName
    {
        get
        {
            return _LastName;
        }
        set
        {
            _LastName = value;

        }
    }
    private String _Address;
    public String Address
    {
        get
        {
            return _Address;
        }
        set
        {
            _Address = value;

        }
    }

    private String _State;
    public String State
    {
        get
        {
            return _State;
        }
        set
        {
            _State = value;

        }
    }

    private String _City;
    public String City
    {
        get
        {
            return _City;
        }
        set
        {
            _City = value;

        }
    }
    private String _ZIP;
    public String ZIP
    {
        get
        {
            return _ZIP;
        }
        set
        {
            _ZIP = value;

        }
    }

       public void Add1()
  {

    newprospect = new Prospect();
    newprospect.ID = Guid.NewGuid();
    newprospect.FirstName = FirstName;
    newprospect.LastName = LastName;
    newprospect.Address = Address;
    newprospect.State = State;
    newprospect.City = City;
    newprospect.ZIP = ZIP;

    prospect = newprospect;
    ctx2.AddToProspects(prospect);
    Prospects.Add(newprospect);
    }

   public event PropertyChangedEventHandler PropertyChanged = delegate { };
   private void RaisePropertyChanged(string property) { PropertyChanged(this, new PropertyChangedEventArgs(property)); }
}

}

My view xamal:

    <Window x:Class="Wpfentity3.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 WindowStartupLocation="CenterScreen"

   Title="Prospects"
   Height="482" Width="500" MaxWidth="500" MaxHeight="600"
   xmlns:cusns="clr-namespace:Wpfentity3">



    <StackPanel Height="290" VerticalAlignment="Top">
    <StackPanel Orientation="Horizontal" >
        <Label
    Content="Prospects"
    BorderBrush="Blue" BorderThickness="1"
    HorizontalAlignment="Left" VerticalAlignment="Top"
    FontSize="24" FontFamily="Comic Sans MS"
    Padding="13,3,13,9" Margin="5"
       Foreground="Purple" Background="LemonChiffon" />
          <Label 
   Content="{Binding Path=label}" Foreground="Red" FontSize="14"
   HorizontalAlignment="Right" VerticalAlignment="Center" 
   Height="auto" Margin="180,0,10,0" />


    </StackPanel>

    <Grid
  HorizontalAlignment="Left" VerticalAlignment="Top"
  Height="120" Width="475" >
        <Grid.RowDefinitions>
            <RowDefinition Height="25*" />
            <RowDefinition Height="25*" />
            <RowDefinition Height="25*" />
            <RowDefinition Height="25*" />

        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="90*" />
            <ColumnDefinition Width="135*" />
            <ColumnDefinition Width="45*" />
            <ColumnDefinition Width="32*" />
            <ColumnDefinition Width="57*" />
            <ColumnDefinition Width="118*" />
        </Grid.ColumnDefinitions>

        <Label
    Content="First name"
    Grid.Row="0" Grid.Column="0" Margin="0,0,5,0"
    HorizontalAlignment="Right" VerticalAlignment="Center" />
        <TextBox Name="txtFirstName" 
    Grid.Column="1"
    HorizontalAlignment="Left" VerticalAlignment="Center" Text="{Binding Path=FirstName}" 
    Width="130" />

        <Label
    Content="Last name"
    Grid.Row="1" Grid.Column="0" Margin="0,0,5,0"
    HorizontalAlignment="Right" VerticalAlignment="Center" />
        <TextBox  Name="txtLastName"
    Grid.Row="1" Grid.Column="1"
    HorizontalAlignment="Left" VerticalAlignment="Center" Text="{Binding LastName}"
    Width="130" />

        <Label
    Content="Address"
    Grid.Row="2" Grid.Column="0" Margin="0,0,5,0"
    HorizontalAlignment="Right" VerticalAlignment="Center" />
        <TextBox  Name="txtAddress"
    Grid.Row="2" Grid.Column="1"
    HorizontalAlignment="Left" VerticalAlignment="Center" Text="{Binding Address}"
    Width="300" Grid.ColumnSpan="5" />

        <Label
    Content="City"
    Grid.Row="3" Grid.Column="0" Margin="0,0,5,0"
    HorizontalAlignment="Right" VerticalAlignment="Center" />
        <TextBox Name="txtCity"
    Grid.Row="3" Grid.Column="1"
    HorizontalAlignment="Left" VerticalAlignment="Center" Text="{Binding City}"
    Width="130" />

        <Label
    Content="State"
    Grid.Row="3" Grid.Column="2" Margin="0,0,5,0"
    HorizontalAlignment="Right" VerticalAlignment="Center" />
        <TextBox Name="txtState"
    Grid.Row="3" Grid.Column="3" Width="30" MaxLength="2" CharacterCasing="Upper" Text="{Binding State}"
    HorizontalAlignment="Left" VerticalAlignment="Center" />

        <Label
       Content="ZIP code"
    Grid.Row="3" Grid.Column="4" Margin="0,0,5,0"
    HorizontalAlignment="Right" VerticalAlignment="Center" />
        <TextBox Name="txtZIP"
    Grid.Row="3" Grid.Column="5" MaxLength="10"
    HorizontalAlignment="Left" VerticalAlignment="Center" Text="{Binding ZIP}"
    Width="90" />

    </Grid>

    <StackPanel Orientation="Horizontal" Margin="0,10,0,0">

        <Button Name="btnFind"
    Content="_Find"
    Width="auto" Margin="5,0,5,0" Padding="10,0,10,0" />
        <Button Name="btnAdd"
    Content="_Add"  Command="{Binding Commands.Add}"
    Width="auto" Margin="5,0,5,0" Padding="10,0,10,0" />
        <Button Name="btnEdit"
    Content="_Edit"
    Width="auto" Margin="5,0,5,0" Padding="10,0,10,0" />
        <Button Name="btnDelete"
    Content="_Delete"
    Width="auto" Margin="5,0,5,0" Padding="10,0,10,0" />
        <Button Name="btnSave"
    Content="_Save"
    Width="auto" Margin="5,0,5,0" Padding="10,0,10,0" />
        <Button Name="btnCancel"
    Content="_Cancel"
    Width="auto" Margin="5,0,5,0" Padding="10,0,10,0" />
        <Button Name="btnClose"
    Content="Cl_ose"
    Width="auto" Margin="5,0,5,0" Padding="10,0,10,0"
    />



    </StackPanel>

    <StackPanel Height="34" Margin="10">
        <Grid Margin="10">
            <ListView Name="lvprospects" ItemsSource="{Binding Prospects}" Margin="0,0,0,-200">
                <ListView.View>
                    <GridView>
                        <GridViewColumn Header="FirstName" Width="120" DisplayMemberBinding="{Binding  FirstName}" />
                        <GridViewColumn Header="LastName" Width="50" DisplayMemberBinding="{Binding LastName}" />
                        <GridViewColumn Header="Address" Width="50" DisplayMemberBinding="{Binding Address}" />
                        <GridViewColumn Header="City" Width="50" DisplayMemberBinding="{Binding City}" />
                        <GridViewColumn Header="State" Width="50" DisplayMemberBinding="{Binding State}" />
                        <GridViewColumn Header="ZIP" Width="50" DisplayMemberBinding="{Binding ZIP}" />
                    </GridView>
                </ListView.View>
            </ListView>
        </Grid>




    </StackPanel>

</StackPanel>

faisal
  • 60
  • 11
  • if you are not adding the new record to the collection, how could you expect a refresh of the control? –  Feb 27 '17 at 09:23

3 Answers3

1

It is fine to add the new item to the DB and then retrieve again the collection with the same refresh method FillProspects:

what you're doing is basically correct.

  • The FillProspects method works, but I foresee some issues with it. Recreating the whole list for every refresh can lead to problems with the view. Selected items become unselected at each refresh, some flickering happens when you hover over items with the cursor, it can even lead to performance issues (the view will freeze for a bit at every refresh). Using something that implements INotifyCollectionChanged is the usual WPF-way. – Tesseract Feb 27 '17 at 10:18
  • @Tesseract here is only one example about the [issues with ObservableCollection](http://stackoverflow.com/questions/42528460/add-a-check-with-messagebox-when-datagrid-is-changed/) when one starts using it extensively - *like I do*... feel free to follow up there, if you have the "*usual WPF-way*" answer :) More generally I'd say that refreshing the new items from the DB is a more *consistent and functional* approach, than doing two *separate and sequential* DB and view updates (like in the accepted answer) –  Mar 01 '17 at 17:24
  • Yeah, I know what you mean, I use ObservableCollection a lot too and it does have some big flaws. However, I've tried (really hard) refreshing the whole thing from DB and found that the results were visualy unacceptable. Now I mostly update my Model & ViewModel from the DB and let Binding do the rest. – Tesseract Mar 01 '17 at 19:56
  • "*Now I mostly update my Model & ViewModel from the DB and let Binding do the rest*" of course, we're on the same page, I do (and suggest) the same –  Mar 01 '17 at 20:00
1

Change the type of the Prospects property from List<Prospect> to ObservableCollection<Prospect>:

private ObservableCollection<Prospect> _prospects = new ObservableCollection<Prospect>();
public ObservableCollection<Prospect> Prospects
{
    get
    {
        return _prospects;
    }
    set
    {
        _prospects = value;
        RaisePropertyChanged("Prospects");
    }
}

And add the new Prospect object to this collection as well in your Add1 method:

public void Add1()
{

    newprospect = new Prospect();
    newprospect.ID = Guid.NewGuid();
    newprospect.FirstName = FirstName;
    newprospect.LastName = LastName;
    newprospect.Address = Address;
    newprospect.State = State;
    newprospect.City = City;
    newprospect.ZIP = ZIP;

    prospect = newprospect;
    ctx2.AddToProspects(prospect);
    Prospects.Add(newprospect);
}

Just adding it to the DbContext doesn't affect the ListView.

mm8
  • 163,881
  • 10
  • 57
  • 88
  • Observable collections is new for me...I have changed the code as you mentioned..but still not working..I have removed the FillProspects() method form my view model completely..Now even in form loading list view is not showing any records..In add method inserting the records in to DB is happening but after that 'Prospects.Add(newprospect); code shows errror :Null reference Exception was un handled Object reference not set to an instance of an object. – faisal Feb 28 '17 at 08:55
  • You need to new up (create an instance of) the ObservableCollection before you add items to it. I edited my answer to clarify this. And of course you need to FillProspects method to load the records from the database and populate the collection initially. – mm8 Feb 28 '17 at 11:36
  • it is working fine...but inotifcation will not refresh value from data base ..So I think it will be better to call method after adding the record .if I am wrong? – faisal Feb 28 '17 at 17:06
  • Of course you need to re-query database each time you want to get the latest data that has not been submitted through your application. – mm8 Feb 28 '17 at 17:08
0

If you're going to bind a view to a collection in your ViewModel, I suggest using an ObservableCollection.
The ObservableCollection implements INotifyCollectionChanged, it notifies the view when elements are added or removed.
With this you should not need your "FillProspects" method and your "RaisePropertyChanged("Prospects")".

If you want more information I suggest posting how you bind in your XAML and also how you construct your "Prospects" object (we don't even know what type it is, I just assume it isn't an ObservableCollection).

EDIT : you bind your ListView to "Prospects", but in your ViewModel, I see that "Prospects" is of type "List", it needs to be "ObservableCollection". I see that you have an ObservableCollection named "prospects", but you don't use it anywhere. Could this be the issue ?

Tesseract
  • 180
  • 11
  • I have used objservable collection : – faisal Feb 27 '17 at 09:40
  • Did you set your DataContext correctly? Can you update your post to show your "AddToProspects" method and how you bind in your XAML? – Tesseract Feb 27 '17 at 09:44
  • I have set my DataContext in the page intiiatives of View cs – faisal Feb 27 '17 at 09:57
  • Thanks alot for your valuable help...I have changed the code as you mentioned..but still not working..I have removed the FillProspects() method form my view model completely..Now even in form loading list view is not showing any records..In add method inserting the records in to DB is happening but after that 'Prospects.Add(newprospect); code shows errror :Null reference Exception was un handled Object reference not set to an instance of an object. – faisal Feb 28 '17 at 08:56
  • Can't help you with a null reference exception if we don't see your code. What _might_ have happened is that either you did not instanciate your private ObservableCollection variable, or you did not return the right variable in your "get" in "Prospects". If that's not it then I really need to see what you did to help you further, maybe update your post with your new code? – Tesseract Feb 28 '17 at 09:06
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/136831/discussion-between-tesseract-and-faisal). – Tesseract Feb 28 '17 at 09:13