多条件下的WPF绑定

6

在我的MVVM中,我在视图中有一个DataGrid,我想根据2个条件启用行元素。DataGrid在其中一个列中有一个复选框(绑定到IsRowChecked属性),并且在另一个列中有一个标题复选框。如果满足以下两个条件,则启用行元素: 1)IsRowChecked为true 2)标题复选框被选中。

这种多条件设置是否可行?

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>

"化学品数量"列只需要单个条件绑定,这是我可以做到的。Value1和Value2需要两个条件即IsRowChecked和标题复选框选中。我可以用单个条件做到,但无法找到实现这两个条件绑定的方法。

我该如何实现这种绑定?

任何帮助都将不胜感激。

谢谢!

1个回答

10

关于绑定中复杂表达式的处理,有两种方法: 一是使用具有转换器的 MultiBinding ,另外一种是使用具有特定情况的 MultiDataTrigger 。 对于您的示例,两者都可以很好地工作。

1. MultiBinding

这种方法几乎适用于任何情况,但需要实现转换器(它们可以被重复使用)。

  1. 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();
        }
    }
    
  2. Add the converter to resources:

    <Window.Resources>
        <local:AndConverter x:Key="convAnd"/>
    </Window.Resources>
    
  3. 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

这种方法适用于只有一个属性值配置需要特定行为的情况。在您的示例中,文本框始终处于禁用状态,除非两个复选框都被选中。语法更加复杂,但是不需要转换器。

  1. 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>
    

哇,Athari,两个选项都完美地工作了。我在想该用哪一个。在这种情况下,我认为我只会使用MultiBinding。还有一个问题,我能否在我的标题复选框上实现相同的功能-如果选择Value1标题chkbox,则只允许用户选择Value2标题复选框。最初,Value2标题chkbox被禁用,当用户选择Value1 chkValue1时,才启用chkValue2。这可以在标题复选框中实现吗? - Tvd
@Tvd 我不是很理解确切的布尔表达式,但无论如何,您可以使用带有转换器的MultiBindingMultiBinding 可以包含任意数量的 Binding,这些值将在 values 参数中传递给 IMultiValueConverter.Convert 方法。在此方法内部,您可以编写任何逻辑表达式。我在 Convert 中使用的代码有点复杂,因为它是通用的并检查所有可能性,但基本上它是 return (bool)values [0] && (bool)values [1] - Athari

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接