Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to do I send validation messages form model to view in the MVVM pattern?

I've got a small test WPF MVVM application working in which a view allows the user to change the first or last names of customers and the full name automatically changes, so communication is going from M-to-MV-to-V and back, everything is fully decoupled, so far so good.

But now as I look to how I will begin extending this to build large applications with the MVVM pattern, I find the decoupling to be an obstacle, namely:

  • how will I do validation messages, e.g. if back in the model in the LastName setter I add code that prevents names over 50 characters from being set, how can I send a messsage to the view telling it to display a message that the name was too long?

  • in complex applications I may have dozens of views on a screen at one time, yet I understand that in MVVM each view has one and only one ViewModel assigned to it to provide it with data and behavior, so how is it that the views can interact with each other, e.g. in the above validation example, what if back in the customer model we want to inform a particular "MessageAreaView" to display the message "Last name may only contain 50 characters.", how to we communicate that up the stack to that particular view?

CustomerHeaderView.xaml (View):

<UserControl x:Class="TestMvvm444.Views.CustomerHeaderView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid>
        <StackPanel HorizontalAlignment="Left">
            <ItemsControl ItemsSource="{Binding Path=Customers}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <StackPanel Orientation="Horizontal">
                                <TextBox
                                Text="{Binding Path=FirstName, Mode=TwoWay}" 
                                Width="100" 
                                Margin="3 5 3 5"/>
                                <TextBox 
                                Text="{Binding Path=LastName, Mode=TwoWay}" 
                                Width="100"
                                Margin="0 5 3 5"/>
                                <TextBlock 
                                Text="{Binding Path=FullName, Mode=OneWay}" 
                                Margin="0 5 3 5"/>
                            </StackPanel>
                        </StackPanel>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </StackPanel>
    </Grid>
</UserControl>

Customer.cs (Model):

using System.ComponentModel;

namespace TestMvvm444.Model
{
    class Customer : INotifyPropertyChanged
    {

        public int ID { get; set; }
        public int NumberOfContracts { get; set; }

        private string firstName;
        private string lastName;

        public string FirstName
        {
            get { return firstName; }
            set
            {
                if (firstName != value)
                {
                    firstName = value;
                    RaisePropertyChanged("FirstName");
                    RaisePropertyChanged("FullName");

                }
            }
        }

        public string LastName
        {
            get { return lastName; }
            set
            {
                if (lastName != value)
                {
                    lastName = value;
                    RaisePropertyChanged("LastName");
                    RaisePropertyChanged("FullName");
                }
            }
        }

        public string FullName
        {
            get { return firstName + " " + lastName; }
        }



        #region PropertChanged Block
        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChanged(string property)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(property));
            }
        }
        #endregion
    }
}
like image 541
Edward Tanguay Avatar asked Mar 01 '23 21:03

Edward Tanguay


1 Answers

For validation, have your view model implement IDataErrorInfo. As for communication between views, don't be afraid to write UI services (eg. a message service that allows and view model to contribute messages that will be displayed somewhere in the UI). Or if there is a hard relationship between view models (eg. one view model owns another) then the owning view model can hold a reference to the child view model.

like image 194
Kent Boogaart Avatar answered Mar 04 '23 11:03

Kent Boogaart