WPF Binding on multiple criterias
There're two ways to work with complex expressions on bindings: MultiBinding
with a converter and MultiDataTrigger
with specific cases. For your example, both work nicely.
1. MultiBinding
This method works for virtually any case, but requires implementing converters (they can be reused, obviously).
Create
AndConverter
class implementingIMultiValueConverter
interface. It needs to returntrue
if all values passed to it are true (DependencyProperty.UnsetValue
is a special value when value is not available).public class AndConverter : IMultiValueConverter { public object Convert (object[] values, Type targetType, object parameter, CultureInfo culture) { if (values.Any(v => ReferenceEquals(v, DependencyProperty.UnsetValue))) return DependencyProperty.UnsetValue; return values.All(System.Convert.ToBoolean); } public object[] ConvertBack (object value, Type[] targetTypes, object parameter, CultureInfo culture) { throw new NotSupportedException(); } }
Add the converter to resources:
<Window.Resources> <local:AndConverter x:Key="convAnd"/> </Window.Resources>
Specify
DataTemplate
forValue1
column (original code is commented):<DataTemplate DataType="local:Item"> <!--<TextBox IsEnabled="{Binding ElementName=chkValue11, Path=IsChecked}" Text="{Binding Path=Value1, Mode=TwoWay}"/>--> <TextBox Text="{Binding Path=Value1, Mode=TwoWay}"> <TextBox.IsEnabled> <MultiBinding Converter="{StaticResource convAnd}"> <Binding ElementName="chkValue11" Path="IsChecked"/> <Binding Path="IsRowChecked"/> </MultiBinding> </TextBox.IsEnabled> </TextBox> </DataTemplate>
2. MultiDataTrigger
This method works when only one property value configuration needs specific behavior. In your example, the text box is always disabled, except when both check boxes are checked. The syntax is more complex, but converters are not required.
Specify
DataTemplate
forValue2
column (original code is commented):<DataTemplate DataType="local:Item"> <!--<TextBox IsEnabled="{Binding ElementName=chkValue12, Path=IsChecked}" Text="{Binding Path=Value2, Mode=TwoWay}"/>--> <TextBox x:Name="txt" Text="{Binding Path=Value2, Mode=TwoWay}" IsEnabled="False"/> <DataTemplate.Triggers> <MultiDataTrigger> <MultiDataTrigger.Conditions> <Condition Binding="{Binding IsChecked, ElementName=chkValue12}" Value="True"/> <Condition Binding="{Binding IsRowChecked}" Value="True"/> </MultiDataTrigger.Conditions> <Setter TargetName="txt" Property="IsEnabled" Value="True"/> </MultiDataTrigger> </DataTemplate.Triggers> </DataTemplate>
Tvd
Updated on June 19, 2022Comments
-
Tvd almost 2 years
In my MVVM, in view I have a DataGrid where I want to enable the row elements based on 2 criteria. DataGrid has checkbox in 1 col (that is bound to IsRowChecked property) and a header checkbox in another col. I want to enable the row element if 1) IsRowChecked is true AND 2) Header checkbox is selected.
Is this multiple criteria setting possible ?
XAML
<DataGrid ItemsSource="{Binding SiList, Mode=TwoWay}" Name="dgvSiSelection"> <DataGrid.Columns> <DataGridCheckBoxColumn Binding="{Binding IsRowChecked, Mode=TwoWay}"/> <DataGridTextColumn Header="" Binding="{Binding Header}" MinWidth="108" IsReadOnly="True"/> <DataGridTemplateColumn> <DataGridTemplateColumn.Header> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition /> </Grid.ColumnDefinitions> <TextBlock Text="Number of Chemicals" Grid.Column="0" /> </Grid> </DataGridTemplateColumn.Header> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <TextBlock Text="{Binding Path=NumberOfCases}" /> </DataTemplate> </DataGridTemplateColumn.CellTemplate> <DataGridTemplateColumn.CellEditingTemplate> <DataTemplate> <TextBox IsEnabled="{Binding Path=IsRowChecked}" Text="{Binding Path=NumberOfCases, Mode=TwoWay}" /> </DataTemplate> </DataGridTemplateColumn.CellEditingTemplate> </DataGridTemplateColumn> <!-- Value1 chkValue11--> <DataGridTemplateColumn> <DataGridTemplateColumn.Header> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <TextBlock Grid.Column="1" Text="Value1" IsEnabled="{Binding ElementName=chkValue11, Path=IsChecked}" /> <CheckBox Name="chkValue11" Grid.Column="0" Width="16" /> </Grid> </DataGridTemplateColumn.Header> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <TextBlock Text="{Binding Path=Value1}" /> </DataTemplate> </DataGridTemplateColumn.CellTemplate> <DataGridTemplateColumn.CellEditingTemplate> <DataTemplate> <TextBox IsEnabled="{Binding ElementName=chkValue11, Path=IsChecked}" Text="{Binding Path=Value1, Mode=TwoWay}" /> </DataTemplate> </DataGridTemplateColumn.CellEditingTemplate> </DataGridTemplateColumn> <!-- Value2 chkValue12--> <DataGridTemplateColumn> <DataGridTemplateColumn.Header> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <TextBlock Grid.Column="1" Text="Value2" IsEnabled="{Binding ElementName=chkValue12, Path=IsChecked}" /> <CheckBox Name="chkValue12" Grid.Column="0" Width="16" /> </Grid> </DataGridTemplateColumn.Header> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <TextBlock Text="{Binding Path=Value2}" /> </DataTemplate> </DataGridTemplateColumn.CellTemplate> <DataGridTemplateColumn.CellEditingTemplate> <DataTemplate> <TextBox IsEnabled="{Binding ElementName=chkValue12, Path=IsChecked}" Text="{Binding Path=Value2, Mode=TwoWay}" /> </DataTemplate> </DataGridTemplateColumn.CellEditingTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid>
"Number of Chemicals" col need only single criteria binding which I could do. Value1 & Value2 needs 2 criteria i.e. of IsRowChecked and header checkbox selected. I could do with single, but can't get a way to implement 2 criteria's in these bindings.
How can I achieve this sort of binding ???
Any help is highly appreciated.
Thanks