WPF MultiDataTrigger AND condition

2019-04-29 16:58发布

问题:

I would like to enable a button only when both of my two datagrids have selected items. Right now it is enabled when either of the datagrids have selections. Any ideas?

<Button x:Name="button" Content="Z" Grid.Column="1" Margin="0,240,0,0" VerticalAlignment="Top" FontFamily="Wingdings 3" FontSize="21.333" ToolTip="Set the selected alarm for the selected alarm time">
                    <Button.Style>
                        <Style TargetType="Button">
                            <Setter Property="IsEnabled" Value="True" />
                            <Setter Property="Opacity" Value="1" />
                            <Style.Triggers>
                                <MultiDataTrigger>
                                    <MultiDataTrigger.Conditions>
                                        <Condition Binding="{Binding ElementName=alarmProfilesDataGrid, Path=SelectedItem}" Value="{x:Null}"/>
                                        <Condition Binding="{Binding ElementName=alarmFilesDataGrid, Path=SelectedItem}" Value="{x:Null}"/>
                                    </MultiDataTrigger.Conditions>
                                    <MultiDataTrigger.Setters>
                                        <Setter Property="IsEnabled" Value="False" />
                                        <Setter Property="Opacity" Value=".5" />
                                        </MultiDataTrigger.Setters>
                                </MultiDataTrigger>
                            </Style.Triggers>
                        </Style>
                    </Button.Style>
                </Button>

回答1:

Here is what happens with your code: Instead of both conditions to be true when either of the datagrids have selections, the conditions are only met when both of the datagrid don't have selections.

When the program starts, both the datagrids are nulls, so your condition is met. Now if you make selection in either of your grids, your condition is never met and the value of IsEnabled remains True i.e. the original value.

To correct this problem, you need a converter:

public class NotNullToBoolConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        bool result = value == null ? false : true;

        return result;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value;
    }
}

and

<Style TargetType="Button">
    <Setter Property="IsEnabled" Value="False" />
    <Setter Property="Opacity" Value=".5" />
    <Style.Triggers>
    <MultiDataTrigger>
        <MultiDataTrigger.Conditions>
        <Condition Binding="{Binding ElementName=alarmProfilesDataGrid, Path=SelectedItem, Converter={StaticResource NotNullToBoolConverter}}" Value="True"/>
        <Condition Binding="{Binding ElementName=alarmFilesDataGrid, Path=SelectedItem, Converter={StaticResource NotNullToBoolConverter}}" Value="True"/>
        </MultiDataTrigger.Conditions>
        <MultiDataTrigger.Setters>
        <Setter Property="IsEnabled" Value="True" />
        <Setter Property="Opacity" Value="1" />
        </MultiDataTrigger.Setters>
    </MultiDataTrigger>
    </Style.Triggers>
</Style>


回答2:

I believe the right way to do this is using Property bindings and a Command with CanExecute conditions which is bound to the Button.

public RelayCommand SaveCommand { get; set; }

SaveCommand = new RelayCommand();
SaveCommand.Action = () => { Save(SelectedObject1,SelectedObject2); };
SaveCommand.CanExecute = () => { SelectedObject1 != null && SelectedObject2 != null) };

XAML:

<DataGrid SelectedItem="{Binding Path=SelectedObject1}">
</DataGrid>
<DataGrid SelectedItem="{Binding Path=SelectedObject2}">
</DataGrid>
<Button Context="Save" Command="{Binding SaveCommand}/>

This will enable the button only when two object is selected from each grid.

PS: This code is not valid but you can find how to use a RelayCommand on SO. Please search for some RelayCommand implementation on SO.