Search code examples
c#wpfmultidatatrigger

C# WPF OR logical gate between ValidationRules


I'm using a combobox with validation and a save button as follows:

<ComboBox   ItemsSource="{Binding ...}" 
            x:Name="cmbGenerationTariff" IsEnabled="False" >
    <ComboBox.SelectedItem>
        <Binding Path="..." UpdateSourceTrigger="PropertyChanged" Mode="TwoWay">
            <Binding.ValidationRules>
                <common:ValidationRuleStringAnyLength  ValidatesOnTargetUpdated="True"/>
            </Binding.ValidationRules>
        </Binding>
    </ComboBox.SelectedItem>
</ComboBox>

...

<Button x:Name="btnSaveSite" Click="btnSave_Click"  Content="SAVE">
    <Button.Style>
        <Style TargetType="{x:Type Button}">
            <Setter Property="IsEnabled" Value="false" />
            <Style.Triggers>
                <MultiDataTrigger>
                    <MultiDataTrigger.Conditions>                           
                        <Condition Binding="{Binding ElementName=cmbGenerationTariff, Path=(Validation.HasError)}" Value="false" />
                        <Condition Binding="{Binding ElementName=cmbTimeZone, Path=(Validation.HasError)}" Value="false" />                         
                        <Condition Binding="{Binding ElementName=txtCity, Path=(Validation.HasError)}" Value="false" />
                        <Condition Binding="{Binding ElementName=cmbCountry, Path=(Validation.HasError)}" Value="false" />
                    </MultiDataTrigger.Conditions>
                    <Setter Property="IsEnabled" Value="true" />
                </MultiDataTrigger>
            </Style.Triggers>
        </Style>
    </Button.Style>
</Button>

And it works just fine. The save button is enabled iff all elements are valid.

What I want is for the save button to be enabled also when elements are disabled (in other words, I don't need to validate the values of disabled elements).

How can I do it? can I maybe use an 'OR' condition (element is valid OR element is disabled)?


Solution

  • As @Adi Lester put it, you'd probably be better off using MVVM pattern here.
    Consider adding e.g. MVVMLight as dependency, via NuGet, to get started easier.

    If you do, you'll have that much better control over your logic. Consider simple Window XAML

    <Window.DataContext>
        <local:MainViewModel />
    </Window.DataContext>
    <StackPanel>
        <!--Bind to Text and IsEnabled properties in ViewModel-->
        <TextBox Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}" 
                 IsEnabled="{Binding IsEnabled}">
        </TextBox>
        <!--Bind to IsEnabled property in ViewModel-->
        <CheckBox Content="Text input enabled" 
                  IsChecked="{Binding IsEnabled}">
        </CheckBox>
        <!--Bind to SaveCommand in ViewModel-->
        <Button Content="Save" 
                Command="{Binding SaveCommand}">
        </Button>
    </StackPanel>
    

    Where MainWindow codebehind is left as-is and MainViewModel (the DataContext) is

    public class MainViewModel : ViewModelBase // <- MVVMLight ViewModel base class
    {
        private string _text = null;
        private bool _isEnabled = true;
    
        public MainViewModel()
        {
            SaveCommand = new RelayCommand(
                // Execute command
                () => Console.WriteLine(@"Save command received, input value:{0}", Text),
                // Can execute command?
                () => !IsEnabled || (IsEnabled && !string.IsNullOrWhiteSpace(Text)));
        }
    
        public ICommand SaveCommand { get; set; }
    
        public string Text
        {
            get { return _text; }
            set { _text = value; RaisePropertyChanged(); }
        }
    
        public bool IsEnabled
        {
            get { return _isEnabled; }
            set { _isEnabled = value; RaisePropertyChanged(); }
        }
    }
    

    Tadah! Now you have logic that toggles your Save button on when either text is entered or checkbox is left unchecked. And as additional bonus you are now officially Doing It Right ;)

    enter image description here