2

Hi I've a datagrid with textbox for receive as input an ip address. To validate the textbox I bound it with my custom validator.

<DataGridTemplateColumn.CellTemplate>
    <DataTemplate>
        <TextBox Margin="20,10,20,10" Height="20" Width="100" HorizontalAlignment="Center" VerticalAlignment="Center" BorderBrush="{Binding Path=IPSrcValidationStatus.Color}">
             <TextBox.Text>
                  <Binding Path="IPSrc" UpdateSourceTrigger="PropertyChanged">
                      <Binding.ValidationRules>
                          <validators:IPv4ValidationRule/>
                              </Binding.ValidationRules>
                       </Binding>
                </TextBox.Text>
             </TextBox>
     </DataTemplate>
</DataGridTemplateColumn.CellTemplate>

How I can access the ValidationResult from my code, or even better, bind it with my view model?

Mafii
  • 7,227
  • 1
  • 35
  • 55
FBGenesy
  • 39
  • 2

1 Answers1

2

Validationrules happen purely in the UI. In a similar way to conversion failures, they set your control as having errors but no transfer of data from view to viewmodel takes place.

As is often the case with wpf, there are several ways of telling your viewmodel there are data errors in the view.

Your validationrule can get the binding expression and set some property on the viewmodel. There's some code in Maxence's post here: Passing state of WPF ValidationRule to View Model in MVVM

I've never used that approach ( but it looks like it'd work ).
I usually want to know about conversion failures as well as any validationrule failures. In scenarios where I use validationrule then I usually only care whether valid data made it to the viewmodel and IsDirty==true

The approach I often use is to get any errors as they bubble up the control tree in a parent grid. This sample here has the code I use:

https://gallery.technet.microsoft.com/scriptcenter/WPF-Entity-Framework-MVVM-78cdc204

I set

NotifyOnSourceUpdated=True,
NotifyOnValidationError=True,

On all bindings I'm interested in. The errors will then bubble up. They are trapped and passed to the viewmodel from a standard template in the resource dictionary. The ConversionErrorCommand will fire with conversion and validation result fails.

    <Grid ...               >
                <i:Interaction.Triggers>
                    <local:RoutedEventTrigger RoutedEvent="{x:Static Validation.ErrorEvent}">
                        <e2c:EventToCommand
                                                Command="{Binding EditVM.TheEntity.ConversionErrorCommand, Mode=OneWay}"
                                                EventArgsConverter="{StaticResource BindingErrorEventArgsConverter}"
                                                PassEventArgsToCommand="True" />
                    </local:RoutedEventTrigger>
                    <local:RoutedEventTrigger RoutedEvent="{x:Static Binding.SourceUpdatedEvent}">
                        <e2c:EventToCommand
                                                Command="{Binding EditVM.TheEntity.SourceUpdatedCommand, Mode=OneWay}"
                                                EventArgsConverter="{StaticResource BindingSourcePropertyConverter}"
                                                PassEventArgsToCommand="True" />
                    </local:RoutedEventTrigger>
                </i:Interaction.Triggers>

You will also need RoutedEventTrigger:

public class RoutedEventTrigger : EventTriggerBase<DependencyObject>
{
    RoutedEvent routedEvent;
    public RoutedEvent RoutedEvent
    {
        get
        {
            return routedEvent;
        }
        set 
        { 
            routedEvent = value;
        }
    }

    public RoutedEventTrigger()
    {
    }
    protected override void OnAttached()
    {
        Behavior behavior = base.AssociatedObject as Behavior;
        FrameworkElement associatedElement = base.AssociatedObject as FrameworkElement;
        if (behavior != null)
        {
            associatedElement = ((IAttachedObject)behavior).AssociatedObject as FrameworkElement;
        } 
        if (associatedElement == null)
        {
            throw new ArgumentException("This only works with framework elements");
        }
        if (RoutedEvent != null)
        {
            associatedElement.AddHandler(RoutedEvent, new RoutedEventHandler(this.OnRoutedEvent));
        }
    }
    void OnRoutedEvent(object sender, RoutedEventArgs args)
    {
         base.OnEvent(args);
    }
    protected override string GetEventName()
    {
        return RoutedEvent.Name;
    }
}

}

Andy
  • 11,864
  • 2
  • 17
  • 20