Question

I got a ViewModel which handles Validation using the IDataErrorInfo Interface. This works fine for ComboBoxes, TextBoxes, Checkboxes, etc.

The DatePicker seems to Validate the Input itself based on the Binding to a "DateTime?" property inside the ViewModel which works fine, too.

Now I want to Disable/Enable a Button using Command Binding from inside the ViewModel. If any Control shows a Validation Error, the Button should be disabled.

Using MVVM-Light's RelayCommand I got this working for anyting but the DatePickers , because they validate themselves.

RelayCommand Code:

this.DoSomethingCommand = new RelayCommand(this.DoSomething, this.CanDoSomething);


Is there a way to get their Validation-State into the ViewModel?
I really appreciate some help on this one!



Before anyone mentions it: I already tried using a Multidatatrigger and therefore Handling the Button IsEnabled Property in the View. It didnt work, IsEnabled was the only Property which i couldnt change using datatriggers. Even without any CommandBindings.(maybe because of my companies Authentication-Framework)

Here is the DataTrigger Code i tried:

    <Button x:Uid="Button_1"
            Content="DoSomething"
            IsDefault="True"
            Command="{Binding DoSomethingCommand}">

        <Button.Style>
            <Style x:Uid="Style_1"
                   TargetType="{x:Type Button}"
                   BasedOn="{StaticResource {x:Type Button}}">
                <Setter x:Uid="Setter_2"
                        Property="IsEnabled"
                        Value="false" />
                <Style.Triggers>
                    <MultiDataTrigger x:Uid="MultiDataTrigger_1">
                        <MultiDataTrigger.Conditions>
                            <Condition x:Uid="Condition_1"
                                       Binding="{Binding (Validation.HasError), ElementName=ComboBox1}"
                                       Value="false" />
                            <Condition x:Uid="Condition_2"
                                       Binding="{Binding (Validation.HasError), ElementName=ComboBox2"
                                       Value="false" />
                            <Condition x:Uid="Condition_3"
                                       Binding="{Binding (Validation.HasError), ElementName=ComboBox3}"
                                       Value="false" />
                            <Condition x:Uid="Condition_4"
                                       Binding="{Binding (Validation.HasError), ElementName=ComboBox4}"
                                       Value="false" />
                            <Condition x:Uid="Condition_5"
                                       Binding="{Binding (Validation.HasError), ElementName=ComboBox5}"
                                       Value="false" />
                            <Condition x:Uid="Condition_6"
                                       Binding="{Binding (Validation.HasError), ElementName=DatePicker1}"
                                       Value="false" />
                            <Condition x:Uid="Condition_7"
                                       Binding="{Binding (Validation.HasError), ElementName=DatePicker2}"
                                       Value="false" />
                        </MultiDataTrigger.Conditions>
                        <Setter x:Uid="Setter_1"
                                Property="IsEnabled"
                                Value="True" />
                    </MultiDataTrigger>
                </Style.Triggers>
            </Style>
        </Button.Style>
    </Button>
Was it helpful?

Solution

Please try this: In Xaml:

  <Grid> 
    <Button IsDefault="True" Content="Login" Height="27" Width="75" CommandParameter="{Binding ElementName=XXXXXXXX}" Command="{Binding LoginCommand, Source={StaticResource LoginController}}" Grid.Column="1" Grid.Row="7"/>

    <Button Content="Cancel" Height="27" Width="75" Grid.Column="3" Grid.Row="7" IsCancel="True">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="Click">
                <i:InvokeCommandAction Command="{Binding CancelCommand,Source={StaticResource LoginController}}"/>
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </Button>
    <Label Foreground="White" Content="User Name:" Grid.Column="1" Grid.Row="1"/>
    <Label Foreground="White" Content="Password:" Grid.Column="1" Grid.Row="3"/>
    <TextBox x:Name="UserName" HorizontalAlignment="Left" Width="130" Height="27" Grid.Column="3" Grid.Row="1" Text="{Binding UserName, Source={StaticResource LoginController}, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=true, NotifyOnValidationError=true}"/>
    <PasswordBox HorizontalAlignment="Left" Width="130" Height="27" w:PasswordHelper.Attach="True" 
     w:PasswordHelper.Password="{Binding Password,Source={StaticResource LoginController}, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,ValidatesOnDataErrors=true, NotifyOnValidationError=true}" Grid.Column="3" Grid.Row="3" />        
</Grid>

In ViewModel:

     public ICommand LoginCommand
    {
        get
        {
            return new RelayCommand(OnLogin, IsEnable);
        }
    }
 public void OnLogin(object param)
    {
        //code
    }
bool IsEnable(object obj)
    {
           //Code for you button enable for example "return false;"
    }

Hope this will help you.

OTHER TIPS

FINAL SOLUTION:

I got it working as required with following code:

View:

    <Button x:Uid="Button_1"
            Content="DoSomething"
            IsDefault="True"
            Command="{Binding DoSomethingCommand}">
        <Button.CommandParameter>
            <MultiBinding x:Uid="MultiBinding_1" Converter="{StaticResource validationConverter}">
                <Binding x:Uid="Binding_1" ElementName="ComboBox1"
                         Path="(Validation.HasError)" />
                <Binding x:Uid="Binding_2" ElementName="ComboBox2"
                         Path="(Validation.HasError)" />
                <Binding x:Uid="Binding_3" ElementName="ComboBox3"
                         Path="(Validation.HasError)" />
                <Binding x:Uid="Binding_4" ElementName="ComboBox4"
                         Path="(Validation.HasError)" />
                <Binding x:Uid="Binding_5" ElementName="ComboBox5"
                         Path="(Validation.HasError)" />
                <Binding x:Uid="Binding_6" ElementName="DatePicker1"
                         Path="(Validation.HasError)" />
                <Binding x:Uid="Binding_7" ElementName="DatePicker2"
                         Path="(Validation.HasError)" />
            </MultiBinding>
        </Button.CommandParameter>                
    </Button>

The ValidationConverter:

public class ValidationConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        foreach (var item in values)
        {
            if ((bool)item == true)
            {
                return true;
            }
        }

        return false;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        List<object> list = new List<object>();

        foreach (var item in targetTypes)
        {
            list.Add(Binding.DoNothing);
        }

        return list.ToArray();
    }
}

CanExecute Method in ViewModel:

private bool CanDoSomething(object obj)
{
    return !(bool)obj;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top