Neil
Neil

Reputation: 177

Prism 6 DelegateCommand ObservesProperty code

Hi Good day i'm just new with WPF and MVVM design pattern and i've learned a lot from the blogs and videos of sir BRIAN LAGUNAS in PRISM.. but just want to ask a noob question..whats wrong with my code it doest work for me... any help is very appreciated thanks. here's my code :

MY VIEW MODEL

public class Person : BindableBase
{
    private myPErson _MyPerson;
    public myPErson MyPerson
    {
        get { return _MyPerson; }
        set
        {
            SetProperty(ref _MyPerson, value);
        }
    }

    public Person()
    {
        _MyPerson = new myPErson();
        updateCommand = new DelegateCommand(Execute, CanExecute).ObservesProperty(() => MyPerson.FirstName).ObservesProperty(() => MyPerson.Lastname);

    //    updateCommand = new DelegateCommand(Execute).ObservesCanExecute((p) => CanExecute); /// JUST WANNA TRY THIS BUT DUNNO HOW
    }

    private bool CanExecute()
    {
        return !String.IsNullOrWhiteSpace(MyPerson.FirstName) && !String.IsNullOrWhiteSpace(MyPerson.Lastname);
    }

    private void Execute()
    {
        MessageBox.Show("HOLA");
    }

    public DelegateCommand updateCommand { get; set; }
}

myModel

Declared to another Class File

public class myPErson : BindableBase
{
    private string _firstName;
    public string FirstName
    {
        get { return _firstName; }
        set
        {
            SetProperty(ref _firstName, value);
        }
    }

    private string _lastname;
    public string Lastname
    {
        get { return _lastname; }
        set
        {
            SetProperty(ref _lastname, value);
        }
    }
}

View Xaml Code

<Window x:Class="Prism6Test.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:myVM="clr-namespace:Prism6Test.ViewModel"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <myVM:Person x:Key="mainVM"/>
    </Window.Resources>
<Grid DataContext="{StaticResource mainVM}">
        <TextBox HorizontalAlignment="Left" Height="23" Margin="217,103,0,0" TextWrapping="Wrap" Text="{Binding MyPerson.FirstName,UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="120"/>
        <TextBox HorizontalAlignment="Left" Height="23" Margin="217,131,0,0" TextWrapping="Wrap" Text="{Binding MyPerson.Lastname,UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="120"/>
        <Button Content="Button" Command="{Binding updateCommand}" HorizontalAlignment="Left" Margin="242,159,0,0" VerticalAlignment="Top" Width="75"/>

    </Grid>
</Window>

I've Already read this but it doesnt work for me.. and cant understand how can i properly code it.. please help me ragarding this matter ..HOPE for any reply soon..thx

ObservesProperty method isn't observing model's properties at Prism 6

Upvotes: 7

Views: 8048

Answers (3)

Winseral
Winseral

Reputation: 1

View Xaml Code

<Window x:Class="Prism6Test.Views.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:myVM="clr-namespace:Prism6Test.ViewModel"
    Title="MainWindow" Height="350" Width="525"> 

You are missing the ViewModelLocator

    xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
    prism:ViewModelLocator.AutowireViewModel="True"

Upvotes: 0

Jens
Jens

Reputation: 2702

First i have to say something about your naming. Name your Classes clear. Call your ViewModel e.g. PersonViewModel or just ViewModel when your application is not that big and not Person, because Person is obviously the Model. Moreover myPErson is a very bad name, because it is very similar to your other Person class and you should PascalCase your class names.

Now to your code. I know nothing about Prism so my code depends on the MVVM pattern only without the support of the Prism Libraries.

First i want to change the Model Person. The class looks very easy in my code (just uses auto properties):

public class Person
{
    public string FirstName { get; set; }

    public string LastName { get; set; }

    public Person()
    {
        this.LastName = string.Empty;
        this.FirstName = string.Empty;
    }
}

The PersonViewModel is a littlebit more complex because it implements the INotifyPropertyChanged interface. I am also using the very common RelayCommand which you can find in the link under the accepted answer.

public class PersonViewModel : INotifyPropertyChanged
{
    private Person person;

    private ICommand updateCommand;

    public PersonViewModel()
    {
        this.Person = new Person();
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public Person Person
    {
        get
        {
            return this.person;
        }

        set
        {
            this.person = value;

            // if you use VS 2015 or / and C# 6 you also could use
            // this.OnPropertyChanged(nameof(Person));
            this.OnPropertyChanged("Person");
        }
    }

    public ICommand UpdateCommand
    {
        get
        {
            if (this.updateCommand == null)
            {
                this.updateCommand = new RelayCommand<Person>(this.OpenMessageBox, this.OpenMessageBoxCanExe);
            }

            return this.updateCommand;
        }
    }

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChangedEventHandler handler = this.PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    private void OpenMessageBox(Person person)
    {
        MessageBox.Show("Hola");
    }

    private bool OpenMessageBoxCanExe(Person person)
    {
        if (person == null)
        {
            return false;
        }

        if (string.IsNullOrWhiteSpace(person.FirstName) || string.IsNullOrWhiteSpace(person.LastName))
        {
            return false;
        }

        return true;
    }
}

I cleared up your View a bit, because it is much shorter now. but all in all everything stayed the same. i just renamed the properties and stuff:

<Window ...>
    <Window.Resources>
        <wpfTesst:PersonViewModel x:Key="ViewModel" />
    </Window.Resources>
    <Grid DataContext="{StaticResource ViewModel}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <TextBox Grid.Row="0" TextWrapping="Wrap" Text="{Binding Person.FirstName, UpdateSourceTrigger=PropertyChanged}" />
        <TextBox Grid.Row="1" TextWrapping="Wrap" Text="{Binding Person.LastName, UpdateSourceTrigger=PropertyChanged}" />
        <Button Grid.Row="2" Content="Button" Command="{Binding UpdateCommand}" CommandParameter="{Binding Person}"/>
    </Grid>
</Window>

All in all i would recommend to you to use the common MVVM pattern without the Prism Library. When you understood MVVM good you still can go for Prism. Hope it helps.

Upvotes: 3

galakt
galakt

Reputation: 1439

1) You can`t use complex datamodel like you want, so try it

private myPErson _MyPerson;
    public myPErson MyPerson
    {
        get { return _MyPerson; }
        set
        {
            if (_MyPerson != null)
                _MyPerson.PropertyChanged -= MyPersonOnPropertyChanged;

            SetProperty(ref _MyPerson, value);


            if (_MyPerson != null)
                _MyPerson.PropertyChanged += MyPersonOnPropertyChanged;
        }
    }

    private void MyPersonOnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
    {
        updateCommand.RaiseCanExecuteChanged();
    }

2) Change your constructor

public Person()
    {
        MyPerson = new myPErson();
        updateCommand = new DelegateCommand(Execute, CanExecute);
    }

Upvotes: 4

Related Questions