0

I have created login authentication using MVVM and it worked fine. This is what I have done:

MainWinodw.xaml

  <Window.Resources>
    <BooleanToVisibilityConverter x:Key="BoolToVis" />
</Window.Resources>
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <TextBlock Grid.Row="0" Grid.Column="0">UserName:</TextBlock>
    <TextBlock Grid.Row="1" Grid.Column="0">Password:</TextBlock>
    <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding UserName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
    <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
    <Label Grid.Row="3" Grid.ColumnSpan="2" Visibility="{Binding isAuthenticated, Converter={StaticResource BoolToVis}}">
        User has been authenticated
    </Label>
    <Label Grid.Row="3" Grid.ColumnSpan="2" Visibility="{Binding LoginFail, Converter={StaticResource BoolToVis}}">
         Please enter valid  UserName and Password
    </Label>

    <Button Grid.Row="2" Grid.Column="1" Content="Authenticate" Command="{Binding LoginCommand}" Margin="3" Width="100" HorizontalAlignment="Right" />
</Grid>

UserViewModel.cs

public class LoginViewModel : INotifyPropertyChanged
{
    private bool _isAuthenticated;
    public bool isAuthenticated
    {
        get { return _isAuthenticated; }
        set
        {
            if (value != _isAuthenticated)
            {
                _isAuthenticated = value;
                OnPropertyChanged("isAuthenticated");
            }
        }
    }

    private bool _loginFail;
    public bool LoginFail
    {
        get { return _loginFail; }
        set
        {
            if (value != _loginFail)
            {
                _loginFail = value;
                OnPropertyChanged("LoginFail");
            }
        }
    }

    private string _username;
    public string UserName
    {
        get { return _username; }
        set
        {
            _username = value;
            OnPropertyChanged("UserName");
        }
    }

    private string _password;
    public string Password
    {
        get { return _password; }
        set
        {
            _password = value;
            OnPropertyChanged("Password");
        }
    }

    public ICommand LoginCommand
    {
        get { return new RelayCommand(param => this.Login()); }
    }

    public void Login()
    {
        //TODO check username and password vs database here.
        //If using membershipprovider then just call Membership.ValidateUser(UserName, Password)
        //if (!String.IsNullOrEmpty(UserName) && !String.IsNullOrEmpty(Password))
        //    isAuthenticated = true;
        isAuthenticated = LoginDataLayer.AuthenticateUser(UserName, Password);
        if(isAuthenticated == true)
        {
            LoginFail = false;
        }
        else
        {
            LoginFail = true;
        }

    }

    #region INotifyPropertyChanged Methods

    public void OnPropertyChanged(string propertyName)
    {
        this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
    }

    protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, args);
        }
    }


    public event PropertyChangedEventHandler PropertyChanged;

    #endregion
}

This is working fine. But as I said I'm new to MVVM. I write model code also in viewmodel. After realizing my mistake I tried to separate model and view model code like this:

UserModel.cs

 public  class UserModel : INotifyPropertyChanged
{
    private bool _isAuthenticated;
    public bool isAuthenticated
    {
        get { return _isAuthenticated; }
        set
        {
            if (value != _isAuthenticated)
            {
                _isAuthenticated = value;
                OnPropertyChanged("isAuthenticated");
            }
        }
    }

    private bool _loginFail;
    public bool LoginFail
    {
        get { return _loginFail; }
        set
        {
            if (value != _loginFail)
            {
                _loginFail = value;
                OnPropertyChanged("LoginFail");
            }
        }
    }

    private string _username;
    public string UserName
    {
        get { return _username; }
        set
        {
            _username = value;
            OnPropertyChanged("UserName");
        }
    }

    private string _password;
    public string Password
    {
        get { return _password; }
        set
        {
            _password = value;
            OnPropertyChanged("Password");
        }
    }

    #region INotifyPropertyChanged Methods

    public void OnPropertyChanged(string propertyName)
    {
        this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
    }

    protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, args);
        }
    }


    public event PropertyChangedEventHandler PropertyChanged;

    #endregion
}

UserViewModel.cs

public void Login()
    {
        UserModel obj = new UserModel();


        obj.isAuthenticated = LoginDataLayer.AuthenticateUser(obj.UserName,obj. Password);
        if(obj.isAuthenticated == true)
        {
           obj.LoginFail = false;
        }
        else
        {
            obj.LoginFail = true;
        }

    }

But I am getting obj.username is null. So can anyone help me how I get model property in view model and how can it update. Please help. Thanks

Jose
  • 1,857
  • 1
  • 16
  • 34
Neelam Prajapati
  • 3,764
  • 3
  • 28
  • 62
  • I dont think thatr you cant keep your both logic together. having the methods in ViewModel is not a problem. You can go ahead with your approach – Apoorv Jul 22 '16 at 06:28
  • but i read on many sites that model and view model must be separate. – Neelam Prajapati Jul 22 '16 at 06:32
  • ok do one thing .. in your UserViewModel.cs replace UserModel obj=new UserModel() with ObservableCollectioncoll=new ObservableCollection(); then try to access the values and see if you are still getting null ? – Apoorv Jul 22 '16 at 06:40
  • I think the problem is on the datacontext. If you have separated model and viewmodel now, you have to change the view to. Look if you are accessing userName getter, because I suspect that you are not. – Jose Jul 22 '16 at 06:42
  • @Kirenenko : sorry i didnt get you.where should i access username getter. i binf already it in view.please eloborate – Neelam Prajapati Jul 22 '16 at 06:45
  • 1
    If your view binds to the model, when the textbox shows the value, it is accessing through the getter. Try debuging and see if it stops in the getter. If not, your binding is not working. – Jose Jul 22 '16 at 06:49
  • 2
    When the model already implements INotifyPropertyChanged for all its properties, it doesn't make much sense to replicate all this in the view model. The most simple approach here would be to derive the view model from the model, like `public class UserViewModel : UserModel { ... }` and define only those properties and method that are not already defined in the model. – Clemens Jul 22 '16 at 06:52
  • yes..i put debugger in model. it dont stop there.so is there problem in view and model binding.but what i m doing wrong? – Neelam Prajapati Jul 22 '16 at 06:52
  • @Clemens : oh.thats worked. thank you soooooooooooo much..so in MVVM we should inherite all viewmodel from respected model generally? – Neelam Prajapati Jul 22 '16 at 07:04
  • You wouldn't do it generally. You might as well use delegation. But as said, if your model already implements INotifyPropertyChanged, it is a perfectly valid approach. – Clemens Jul 22 '16 at 07:06
  • 1
    So what would be the correct way to do it? And what if your view accesses data from 2 different models? – Jose Jul 22 '16 at 07:09
  • @Clemens : i m still little confused about model and view model realtionship..as model contains all property so obviuslly we should implemnt inotifypropertychanged... so and obviously we need to access this property in vewmodel .so inheriting model is best way to do that?this is the main relation between both? – Neelam Prajapati Jul 22 '16 at 07:09
  • 1
    Think about having a model that does not implement INotifyPropertyChanged, e.g. a generated DAO. Then you would use [delegation/composition](http://stackoverflow.com/questions/49002/prefer-composition-over-inheritance) instead of inheritance. MVVM does not define a "preferred" or "correct" way. – Clemens Jul 22 '16 at 07:24

1 Answers1

0

As I see it, your view datacontext is the viewModel, but the properties are on the Model. Make your UserModel accesible from the View Model, like this:

ViewModel:

private UserModel _userModel;
public UserModel userModel
{
    get { return _userModel; }
    set
    {
        _userModel = value;
        OnPropertyChanged("userModel");
    }
}

View:

<TextBox Text="{Binding userModel.UserName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
Jose
  • 1,857
  • 1
  • 16
  • 34