Jyotirmaya Prusty
Jyotirmaya Prusty

Reputation: 288

Save data to Collection and Display using MVVM WPF

I have my Model class which implements INotifyPropertyChanged. My View has 5 TextBox, 2 Button and a ListView to display grid. In my ViewModel I was previously adding default values to the ObservableCollection of my Model class and displaying it to a ListView.

The button implementation is done using ICommand and RelayCommand.

Now I want to add data to the ObservableCollection from the user from the UI TextBox. How can I achieve that? The UI TextBox hasbindings with properties of the Model class.

My View

<ListView Name="UserGrid" Grid.Row="1" Margin="4,178,12,13"  ItemsSource="{Binding UserDatas}"  >
<TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="80,7,0,0" Name="txtUserId" VerticalAlignment="Top" Width="178" Text="{Binding UserId}" />
<TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="80,35,0,0" Name="txtFirstName" VerticalAlignment="Top" Width="178" Text="{Binding FirstName}" />

Like these there are 5 TextBoxes

The Model class:

public class User : INotifyPropertyChanged
{
    private int userId;
    private string firstName;


public int UserId
    {
        get
        {
            return userId;
        }
        set
        {
            userId = value;
            RaisePropertyChanged("UserId");
        }
    }
}

The ViewModel:

public class UsersViewModel:INotifyPropertyChanged
{
    private ObservableCollection<User> userDatas;

    public ObservableCollection<User> UserDatas
    {
        get
        {
            if (userDatas == null)
            {
                userDatas = new ObservableCollection<User>();
            }
            return userDatas;
        }
        set
        {
            userDatas = value;
            RaisePropertyChanged("UserDatas");
        }
    }

}

   private CommandBase _LoadCommand;
   public ICommand LoadCommand
    {
        get
        {
            if (this._LoadCommand == null)
                this._LoadCommand = new CommandBase(LoadData);
            return this._LoadCommand;
        }
    }

   private void LoadData(object obj)
   {
        //What need to be done here to access the textboxes of UI which are binded to User.cs class.

       User newUser = new User();
       UserDatas.Add(newUser);
   }

Now what I need to write in the LoadData method to take inputfrom textboxes from UI and store it in my ObservableCollection

Upvotes: 1

Views: 1724

Answers (1)

Tseng
Tseng

Reputation: 64298

There are several things you can do. Most obvious, is to have a "Add New" Command, which creates a new empty object and stores it in a CurrentUser or SelectedUser property.

This property is bound to the Template's (or Form's) context. You'd have 3 commands (Add New User, Save User, Cancel to cancel addition of a new user creation).

For example

public class UsersViewModel : INotifyPropertyChanged
{
    public UsersViewModel() 
    {
        UserDatas = new ObservableCollection<User>();

        AddNewUserCommand = new RelayCommand(AddNewUser, param => !this.IsNewUser);
        SaveUserCommand = new RelayCommand(SaveUser);
        CancelNewUserCommand = new RelayCommand(CancelNewUser, param => this.IsNewUser);
    }

    private ObservableCollection<User> userDatas;
    public ObservableCollection<User> UserDatas
    {
        get { return userDatas; }
        set
        {
            userDatas = value;
            RaisePropertyChanged("UserDatas");
        }
    }

    private User selectedUser;
    public User SelectedUser 
    {
        get { return selectedUser; }
        set
        {
            selectedUser = value;
            RaisePropertyChanged("SelectedUser");
            RaisePropertyChanged("IsNewUser");
        }
    }

    public bool IsNewUser 
    {
        get 
        {
            if(SelectedUser==null)
                return false;

            return SelectedUser.UserId == 0;
        }
    }

    public ICommand AddNewUserCommand { get; private set; }
    public ICommand CancelNewUserCommand { get; private set; }
    public ICommand SaveUserCommand { get; private set; }

    private void AddNewUser() 
    {
        SelectedUser = new User();
    }

    private void SaveUser() 
    {
        // Just in case of concurency
        var newUser = SelectedUser;
        if(newUser == null) 
        {
            return;
        }

        var isNewUser = newUser.UserId == 0;

        // Persist it to the database
        this.userRepository.Add(newUser);
        this.userRepository.SaveChanges();

        // If all worked well, add it to the observable collection
        if(isNewUser) 
        {
            // Only add if new, otherwise it should be already in the collection
            UserDatas.Add(newUser)
        }
    }
}

But again, it's very discouraged to work directly on the model and bind it to the View. You should also create a ViewModel for your User and put validation (implement the IDataErrorInfo interface on the UserViewModel) in there and handling of state, for example tracking if the UserViewModel is dirty (i.e. data was changed).

All these are presentation concerns and not business logic, so they belong to a ViewModel and not to the Model itself.

Upvotes: 1

Related Questions