New in MVVM Doubt with inotifypropertychanged

3

I have a doubt; How to implement the MVVM pattern correctly?

I have a model; User, with the properties; Name, password.

In the ViewModel I create the full Users property in an observable collection , here I inherit the bindablebase with its InotifyPropertyChange

In the view I do Binding in two TextBox ; User.name and User.password.

But the change is not notified when writing in textbox .

Where do I have to notify the changes in the Model or VisualModel ?

How should I do this correctly?

This is the code

Model

public class UsuarioModel
{
    public string Nombre{get;set;}
    public string Password { get; set; }
}

ViewModel

    public DelegateCommand MouseLeftButtonDown { get;private set; }
    public DelegateCommand Salir { get; private set; }
    public DelegateCommand Login { get; private set; }
    public DelegateCommand PasswordChanged {get;set;}

    private UsuarioModel _usuario;          
    public UsuarioModel Usuario
    {
        get { return _usuario; }
        set {SetProperty(ref _usuario, value); }
    }

    public LoginVM()
    {
        MouseLeftButtonDown = new        DelegateCommand(MouseLeftButtonDownExecute,MouseLeftButtonDownCanExecute);
        Salir = new DelegateCommand(SalirExecute, SalirCanExecute);
        Login = new DelegateCommand(LoginExecute, LoginCanExecute);
        PasswordChanged = new DelegateCommand(PasswordChangedExecute, PasswordChangedCanExecute);
        Usuario = new UsuarioModel();
    }

View

    <Label Content="Usuario:" Grid.Row="0" FontSize="16" FontWeight="Bold" Foreground= "#FFFF5254" Margin="15,0,0,0"></Label>
            <Border  Grid.Row="1" Margin="15,0,15,0" Background="#FFDCD4D4" CornerRadius="10">
                <TextBox  Background="#FFDCD4D4" Margin="10,0,10,0" FontSize="15" Foreground="#FFA82020" BorderBrush="{x:Null}" SelectionBrush="{x:Null}" TabIndex="1" BorderThickness="0" Text="{Binding Usuario.Nombre,Mode=TwoWay}"/>
            </Border>
            <Label Content="Contraseña:" Grid.Row="2" FontSize="16" FontWeight="Bold" Foreground="#FFFF5254" Margin="15,0,0,0"></Label>
            <Border Grid.Row="3" Background="#FFDCD4D4" Margin="15,0,15,0" CornerRadius="10">
                <PasswordBox  Margin="10,0,10,0" Background="#FFDCD4D4"    FontSize="15" Foreground="#FFA82020" BorderBrush="{x:Null}" SelectionBrush="{x:Null}" TabIndex="2" BorderThickness="0">
                    <i:Interaction.Triggers>
                        <i:EventTrigger EventName="PasswordChanged">
                            <i:InvokeCommandAction Command="{Binding PasswordChangedCommand}" CommandParameter="{Binding ElementName=txtPassword}"/>
                        </i:EventTrigger>
                    </i:Interaction.Triggers>
                </PasswordBox>
            </Border>
    
asked by Marcos 23.06.2016 в 16:31
source

2 answers

2

You should evaluate if you have the Mode = TwoWay assigned to the textbox binding

WPF - Data Binding

As you will notice in the article, it uses Binding

<TextBox Name = "nameText" Grid.Column = "1" Margin = "2" 
     Text = "{Binding Name, Mode = TwoWay}"/>  

> > Where do I have to notify changes in the Model or in the VisualModel?

You should do it in the property that is updated by launching the notification on the entity itself

The issue is that in your case perhaps the entity is separated from the others that should receive the notification. The serious question you need to notify that the property changed? because by the description you make I do not see it necessary.

> > > > > > > > If I write in the textbox the name appears fine, but if I write it in the property, it does not update the texbox.

In the Set of the property, for example Name of UserModel you must launch the NotifyPropertyChange so that the textbox finds out about the change and reflects it on the screen

How to: Implement the INotifyPropertyChanged interface

    
answered by 23.06.2016 в 17:10
1

Create a view (window, user control, etc) - folder views . Create a base class, in this case "User" - models folder . Create a class that will be ViewModel 'UserViewModel' - viewmodels folder

In 'UserViewModel' create an object 'User' AS PROPERTY, follow this nomenclature

private Usuario _usuarioActual;
public Usuario UsuarioActual
{
    get { return _usuarioActual; }
    set
    {
        _usuarioActual = value;
        if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("UsuarioActual"));
    }
}

If you work with a list of users, add it as ObservableCollection

private ObservableCollection<Usuario> _listaUsuarios;
public ObservableCollection<Usuario> ListaUsuarios = new ObservableCollection<Usuario>();
{
    get { return _listaUsuarios; }
    set
    {
        _listaUsuarios = value;
        if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("ListaUsuarios"));
    }
}

Notice that in the SET you can control the change of value after it is assigned and do things with them, for example

set
{       
    if(value.Edad < 18)
    {
        DenegarAcceso();
    }
    else    
    {
    _usuarioActual = value;
    if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("UsuarioActual"));
    }
}

To avoid problems always initialize the collections directly. . The clicks of the buttons are handled with ICommands, but that is for a longer post ..

Go to the view, in this case a window, and reference the ViewModel

<Window.Resources>
    <ResourceDictionary>                        
        <!-- ViewModels -->
        <vm:MyViewModel x:Key="MyVM" />
    </ResourceDictionary> 
</Window.Resources>

To the main grid you can assign it the DataContext or if there will be more than one ViewModel involved assign it where appropriate.

<Grid DataContext="{StaticResource MyVM}">
...
</Grid>

Then in the buttons you do not give them events, you assign them a 'Command', you can add a parameter to the Command, for example here I assign a command that is in the ViewModel and also send the same button as a parameter

<Button Command="{Binding MyCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Self}}" />

If you do not assign the DataContext to the whole view, but this button if it is connected to the ViewModel you add it

<Button DataContext="{StaticResource MyVM}" Command="{Binding MyCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Self}}" />

Add a listbox and assign the user list that is in the ViewModel

<ListBox  ItemsSource="{Binding ListaUsuarios}" SelectedItem="{Binding UsuarioActual, Mode='TwoWay'}" />

With Mode = 'TwoWay' you tell him that the changes will be in both directions, from the UI to the ViewModel and vice versa. Use twoway mode whenever you need that. You can also add an int property in the viewmodel pair Bin it to the 'SelectedIndex' in the listbox

SelectedItem="{Binding IndiceActual}"

All the methods you put in the ViewModel or in the Model depending on where they belong.

If you need to access the Model from the CodeBehind of the view (you should not, but you can) you can do it by creating an object of the same type as PROPERTY in the code behind and then in the constructor assign the memory address of the ViewModel as a value that is already initialized in the view (in xaml)

private AppLogViewModel _myVM;
public AppLogViewModel MyVM
{
     get { return _myVM; }
     set { _myVM= value; }
}

MyVM= (MyViewModel)FindResource("MyVM");

If you are going to need to use the ViewModel in several views it is better not to reference them every time in cadsa vista because that will create a new instance of the ViewMode, better declare it in the XAML tags of the class App.xaml

That's all the help I can offer for now to unveil a bit the theme of the MVVM pattern and the NotifyPropertyChanged, the trick is to declare the event in each object so that your changes are transmitted to the interface.

I left the Commands pending. Greetings.

    
answered by 07.12.2016 в 05:13