在使用xaml在datagrid中选择行之后,在DataGridTemplateColumn中更改复选框状态

时间:2018-01-17 10:29:29

标签: c# wpf xaml datagrid

我正在创建一个wpf应用程序,并且现在有时会遇到这个问题。 我有一个DataGridTemplateColumn数据网格,其中包含一个复选框和文本块。

  <DataGrid
        Name="ChargeDataGrid"
        Grid.Row="1"
        AutoGenerateColumns="False">
        <DataGrid.Columns>
            <DataGridTemplateColumn Width="*">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <CheckBox x:Name="CheckBox1"/>
                            <TextBlock Text="{Binding}" />
                        </StackPanel>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
                <DataGridTemplateColumn.HeaderTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <CheckBox />
                            <TextBlock Text="Title" />
                        </StackPanel>
                    </DataTemplate>
                </DataGridTemplateColumn.HeaderTemplate>
            </DataGridTemplateColumn>
        </DataGrid.Columns>
        <system:String>123</system:String>
        <system:String>124</system:String>
        <system:String>125</system:String>
        <system:String>126</system:String>
        <system:String>127</system:String>
    </DataGrid>

我需要实现的是当单击行时,此行中的复选框也必须处于选中状态。 我尝试使用样式触发器:

<Style TargetType="{x:Type DataGridCell}">
    <Style.Triggers>
        <Trigger Property="IsSelected" Value="True">
            <Setter Property="CheckBox1.IsChecked" Value="True" />
            <Setter Property="Background" Value="Blue" />
        </Trigger>
    </Style.Triggers>
</Style>

但似乎没有可能像这样更改复选框状态。我知道如何在代码隐藏或mvvm风格中做到这一点,但在这种情况下,我想知道是否可以只使用xaml?

任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:1)

我认为它可以像这样简单地完成:

<CheckBox x:Name="CheckBox1" IsChecked="{Binding RelativeSource={RelativeSource AncestorType=DataGridRow}, Path=IsSelected}"/>

修改

如果所需的结果只是在(重新)选择行时更改IsChecked状态,则可以使用DependencyObject(例如包含窗口)上的附加属性来完成,如下所示:

1)将复选框定义为:

<CheckBox x:Name="CheckBox1" IsEnabled="true" local:MainWindow.CheckboxChecked="{Binding RelativeSource={RelativeSource AncestorType=DataGridRow}, Path=IsSelected,Mode=OneWay}">

2)将附加属性定义为:

public static bool GetCheckboxChecked(DependencyObject obj)
{
  return (bool)obj.GetValue(CheckboxCheckedProperty);
}

public static void SetCheckboxChecked(DependencyObject obj, bool value)
{
  obj.SetValue(CheckboxCheckedProperty, value);
}

public static readonly DependencyProperty CheckboxCheckedProperty =
    DependencyProperty.RegisterAttached("CheckboxChecked", typeof(bool), typeof(MainWindow), new PropertyMetadata(false, CheckboxChecked_Changed));
private static void CheckboxChecked_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
  CheckBox chk = d as CheckBox;
  if (chk != null && chk.Tag == null)
  {
    bool chkValue = chk.IsChecked.GetValueOrDefault();
    bool oldValue = (bool)e.OldValue;
    bool newValue = (bool)e.NewValue;
    chk.Tag = true; // Just to prevent an infinite loop
    chk.IsChecked = !chkValue && !newValue || chkValue && !oldValue && newValue ? false : true;
    chk.Tag = null;
  }
}

答案 1 :(得分:1)

我很害怕,但是使用简单的标准XAML,你无法做到。 我认为你有两种选择:

  1. 您可以使用一些扩展库来扩展绑定功能。某些功能可以在MugenMvvmToolkit
  2. 等mvvm框架中找到
  3. 第二种选择是为此目的使用一些转换器。
  4. 我对第二个变体的解决方案是一种破解,在我看来,更优雅的方式是使用代码。转换器:

    public class MultiValueConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {  
            if (values.Length != 3) throw new ArgumentException("Should be 3 params");
            if (!(values[2] is FrameworkElement element)) return values[1];
    
            if (!(bool)values[0])
            {
                element.Tag = "Value need to be changed.";
                return values[1];
            }
    
            if (element.Tag.Equals("Value changed.")) return values[1];
            var res = !(bool)(values[1] ?? true);
            element.Tag = "Value changed.";
            return res;
        }
    
        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    

    转换器反转bool变量并将之前的状态保存在控件的Tag属性中。这仍然不是代码背后和相当可重用的解决方案。您可以在需要此类行为的任何其他视图中使用此类转换器

    在XAML中,我只更改了复选框控件定义:

    <CheckBox x:Name="RowCheckBox" IsHitTestVisible="False">
        <CheckBox.IsChecked>
            <MultiBinding Converter="{StaticResource MultiValueConverter}" Mode="OneWay">
                <Binding Path="IsSelected" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type DataGridRow}}" />
                <Binding Path="IsChecked" RelativeSource="{RelativeSource Self}" />
                <Binding Mode="OneWay" RelativeSource="{RelativeSource Self}" />
            </MultiBinding>
        </CheckBox.IsChecked>
    </CheckBox>