1

I have created the following view in XAML:

<UserControl x:Class="CatalogEditor.NewAnswer"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:local="clr-namespace:CatalogEditor"
             mc:Ignorable="d"
             x:Name="UserControl"
             d:DesignWidth="640" d:DesignHeight="480">

    <Grid x:Name="LayoutRoot">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="1*"/>
        </Grid.RowDefinitions>

        <Label Content="Question:" Grid.Row="0" Margin="4" HorizontalAlignment="Right" VerticalAlignment="Center"/>
        <TextBlock Margin="4" Grid.Column="1" Grid.Row="0" Text="{Binding QuestionName, Mode=OneWay}"/>

        <Label Content="Name:" Grid.Row="1" Margin="4" HorizontalAlignment="Right" VerticalAlignment="Center"/>
        <TextBox Margin="4" Grid.Column="1" HorizontalAlignment="Left" MinWidth="300" MaxLength="50" Grid.Row="1" Padding="4,2">
            <TextBox.Text>
                <Binding Path="Name" NotifyOnValidationError="True">
                    <Binding.ValidationRules>
                        <local:RequiredRule />
                        <local:NoSpacesRule />
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>     
        </TextBox>

        <Label Content="Display:" Grid.Row="2" Margin="4" HorizontalAlignment="Right" VerticalAlignment="Center"/>
        <TextBox Margin="4" Grid.Column="1" HorizontalAlignment="Left" MinWidth="400" MaxLength="100" Grid.Row="2" Padding="4,2">
            <TextBox.Text>
                <Binding Path="EnglishDisplay" NotifyOnValidationError="True">
                </Binding>
            </TextBox.Text>     
        </TextBox>

        <Label Content="Display (Metric):" Grid.Row="3" Margin="4" HorizontalAlignment="Right" VerticalAlignment="Center"/>
        <TextBox Margin="4" Grid.Column="1" HorizontalAlignment="Left" MinWidth="400" MaxLength="100" Grid.Row="3" Padding="4,2">
            <TextBox.Text>
                <Binding Path="MetricDisplay" NotifyOnValidationError="True">
                </Binding>
            </TextBox.Text>     
        </TextBox>

        <StackPanel HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Row="5" Grid.Column="2" Orientation="Horizontal" Margin="2,0">
            <Button Content="Cancel" Width="75" Margin="2,4" Command="{Binding CancelCommand, Mode=OneWay}"/>
            <Button Content="Add" Width="75" Margin="2,4" FontWeight="Bold" Command="{Binding SaveCommand, Mode=OneWay}"/>
        </StackPanel>
    </Grid>
</UserControl>

The issues I have is that when I am adding a new answer, the properties to which this view is bound are by default invalid. How do I get the validation to indicate this. In other words, how do I force the validation rules to apply to the properties when the form is first loaded? If its not obvious I am using MVVM. Here is my view model. It's pretty straight forward.

public class AnswerViewModel
{
    private readonly Answer _answer;

    private string _name;
    private string _englishDisplay;
    private string _metricDisplay;

    public RelayCommand SaveCommand { get; private set; }
    public RelayCommand CancelCommand { get; private set; }

    public AnswerViewModel(Answer a_answer)
    {
        _answer = a_answer;

        Name = a_answer.Name;

        EnglishDisplay = a_answer.EnglishDisplay;

        MetricDisplay = a_answer.MetricDisplay;

        QuestionName = a_answer.Question.Name;

        SaveCommand = new RelayCommand(OnSaveCommandExecuted);
        CancelCommand = new RelayCommand(OnCancelCommandExecuted);
    }

    public AnswerViewModel()
    {
        _answer = new Answer();
    }

    public Answer Answer
    {
        get { return _answer; }
    }

    public String QuestionName { get; private set; }

    public String Name
    {
        get { return _name; }
        set { _name = value; RaisePropertyChanged(() => Name); }
    }

    public String EnglishDisplay
    {
        get { return _englishDisplay; }
        set { _englishDisplay = value; RaisePropertyChanged(() => EnglishDisplay); }
    }

    public String MetricDisplay
    {
        get { return _metricDisplay; }
        set { _metricDisplay = value; RaisePropertyChanged(() => MetricDisplay); }
    }

    private void OnSaveCommandExecuted()
    {
       _answer.Name = Name;
       _answer.EnglishDisplay= EnglishDisplay;
       _answer.MetricDisplay= MetricDisplay;

       // Navigate away.
    }

    private void OnCancelCommandExecuted()
    {
       // Navigate away.
    }

}
Jordan
  • 9,642
  • 10
  • 71
  • 141

2 Answers2

1

You'll have to add ValidatesOnTargetUpdated="True" on your ValidationRule xaml to force the rule to run when target object is updated. Then, when you first load the datacontext, you have to fire a property changed event on the properties you need to be validated to recalculate the validation rules.

M.G.E
  • 371
  • 1
  • 10
0

I am going to attempt an answer here, but I am not 100% sure I follow your question.

If you want to force a validation on the model, you must manually fire a binding update, you can do this via:

somControl.GetBindingExpression(TextBox.TextProperty).UpdateSource();

(from:) Force validation on bound controls in WPF

You would do this in the onload of the UserControl's Loaded event.

Is this what you are looking for?

Community
  • 1
  • 1
Mark
  • 14,820
  • 17
  • 99
  • 159
  • That might work. I don't like putting code in the code behind if I can help it. What I'm looking for seems like it should be an obviously part of the validation system. Say my user wants to create a new entity. I provided them with a blank new entity entry form that looks very much like the edit entity form, but by default the form doesn't have anything in the Name field. This field has a required rule. I want to prevent my user for handing in the empty form. How would you handle this seemingly common scenario? I'd like to keep the validation logic in the view if possible. Thanks. – Jordan Dec 19 '14 at 14:26
  • So I think the key here is to make use of `IDataErrorInfo`, you an still maintain low level control over your viewmodel in order to prevent the form from being submitted. There are a lot of blogs on it, but here is a good start: http://blog.magnusmontin.net/2013/08/26/data-validation-in-wpf/ – Mark Dec 21 '14 at 01:02