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
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 implementing IMultiValueConverter
interface. It needs to return true
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
for Value1
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
for Value2
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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With