WPF GridView与多个复选框列和选择所有列标题

时间:2011-05-11 19:08:46

标签: c# wpf listview checkbox

我有一个包含多个GridViewColumns的ListView。其中几列是复选框。每个列标题也包含一个复选框,目的是检查/取消选中该列中的所有复选框。每行的复选框都绑定到视图模型中的属性。我已经看过几个帖子,其中的场景是一列复选框,但这些解决方案都不适用于我,因为我有4列复选框。我还需要保持从一次访问到下一次访问的选择状态(可以检查列中的所有,一些或没有复选框)。

这是我的ListView的XAML的缩写版本:

<ListView ItemsSource="{Binding AveragingParameters}">
  <ListView.View>
    <GridView AllowsColumnReorder="False">

      <GridViewColumn Header="Parameter">
        <GridViewColumn.CellTemplate>
          <DataTemplate>
            <DockPanel>
              <TextBlock Text="{Binding Name}" />
            </DockPanel>
          </DataTemplate>
        </GridViewColumn.CellTemplate>
      </GridViewColumn>

      <GridViewColumn>
        <GridViewColumn.CellTemplate>
          <DataTemplate>
            <Grid HorizontalAlignment="Stretch">
              <CheckBox  x:Name="chkAvg" IsChecked="{Binding CalcAverage}" />
            </Grid>
          </DataTemplate>
        </GridViewColumn.CellTemplate>
        <Grid>
          <CheckBox x:Name="chkAvgSelectAll" Content="Avg" ToolTip="Select All" />
        </Grid>
      </GridViewColumn>

      <GridViewColumn>
        <GridViewColumn.CellTemplate>
          <DataTemplate>
            <Grid HorizontalAlignment="Stretch">
              <CheckBox  x:Name="chkMin" IsChecked="{Binding CalMin}" />
            </Grid>
          </DataTemplate>
        </GridViewColumn.CellTemplate>
        <Grid>
          <CheckBox x:Name="chkMinSelectAll" Content="Min" ToolTip="Select All" />
        </Grid>
      </GridViewColumn>

    </GridView>
  </ListView.View>
</ListView>

我尝试在Checked属性上使用命令和命令参数,PropertyChanged事件,并在我的代码后面处理Checked事件,但没有任何东西给我足够的信息来知道我必须在集合中更改的内容。

我想我可以为每个创建一个单独的事件处理程序,但我希望能够在单个事件处理程序中处理这个,如果可能的话,因为最终我将创建一个更容易受到攻击的自定义控件显示的列的条款。

提前致谢

3 个答案:

答案 0 :(得分:1)

我使用Command以及包含我想要设置的模型属性名称的Tag以及设置为绑定到Tag和Checkbox的IsSelected属性的多绑定的CommandParame解决了我的问题。代码如下:

My View的Xaml资源:

<UserControl.Resources>
   <converters:NameValueMultiBindingConverter x:Key="SelectAllConverter" />
</UserControl.Resources>

My View的Xaml:

<ListView ItemsSource="{Binding AveragingParameters}">
  <ListView.View>
    <GridView AllowsColumnReorder="False">

      <GridViewColumn Header="Parameter">
        <GridViewColumn.CellTemplate>
          <DataTemplate>
            <DockPanel>
              <TextBlock Text="{Binding Name}" />
            </DockPanel>
          </DataTemplate>
        </GridViewColumn.CellTemplate>
      </GridViewColumn>

      <GridViewColumn>
        <GridViewColumn.CellTemplate>
          <DataTemplate>
            <Grid HorizontalAlignment="Stretch">
              <CheckBox  x:Name="chkAvg" IsChecked="{Binding CalcAverage}" />
            </Grid>
          </DataTemplate>
        </GridViewColumn.CellTemplate>

        <CheckBox x:Name="chkAvgSelectAll" Content="Avg" 
                  Tag="CalcAvg" Command="SelectAllCheckedCommand" 
                  ToolTip="Select All">
            <MultiBinding Converter="{StaticResource SelectAllConverter}">
              <Binding Path="Tag" RelativeSource="{RelativeSource self}" />
              <Binding Path="IsChecked" RelativeSource="{RelativeSource self}" />
            </MultiBinding>
        </CheckBox>
      </GridViewColumn>

      <GridViewColumn>
        <GridViewColumn.CellTemplate>
          <DataTemplate>
            <Grid HorizontalAlignment="Stretch">
              <CheckBox  x:Name="chkMin" IsChecked="{Binding CalMin}" />
            </Grid>
          </DataTemplate>
        </GridViewColumn.CellTemplate>

        <CheckBox x:Name="chkMinSelectAll" Content="Avg" 
                  Tag="CalcMin" Command="SelectAllCheckedCommand" 
                  ToolTip="Select All">
            <MultiBinding Converter="{StaticResource SelectAllConverter}">
              <Binding Path="Tag" RelativeSource="{RelativeSource self}" />
              <Binding Path="IsChecked" RelativeSource="{RelativeSource self}" />
            </MultiBinding>
        </CheckBox>
      </GridViewColumn>

    </GridView>
  </ListView.View>
</ListView>

我的MultiValueConverter:

public class NameValueMultiBindingConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter,
                          System.Globalization.CultureInfo culture)
    {

        var parameters = (object[])values;
        return new NameValueConverterResult 
                        { 
                           Name = (string)parameters[0], 
                           Value = parameters[1] 
                        };
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, 
                                System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

我在转换器中使用的结果对象:

public class NameValueConverterResult
{
    //The name of the model property to set
    public string Name { get; set; }

    //The value we're setting it to
    public object Value { get; set; }
}

我的视图模型中的DelegateCommand(我正在使用PRISM)和处理程序

public ICommand SelectAllCheckedCommand { get; private set; }
private void OnSelectAllCheckedCommand(object arg )
{
   if (arg == null || !(arg is NameValueConverterResult)) return;

   NameValueConverterResult prop = arg as NameValueConverterResult;

   //Reflect on the model to find the property we want to update.
   PropertyInfo propInfo = Averagers.FirstOrDefault().GetType().GetProperty(prop.Name);
   if (propInfo == null) return;

   //Set the property on the Model
   foreach (var item in Averagers)
      propInfo.SetValue(item, prop.Value, null);
} 

我希望我不会滥用StackOverflow提供我想出的解决方案。我不确定这里的礼节。

答案 1 :(得分:0)

只需交出尽可能多的信息,然后通过反思来完成其余工作,例如

<ListView ItemsSource="{Binding DpData}">
    <ListView.View>
        <GridView>
            <GridViewColumn>
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <CheckBox IsChecked="{Binding IsActive}"/>
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
                <!-- Pass collection to Tag property, relevant member info is in the Content,
                     could also create an array in the Tag if the Content should be a nicer
                     looking string. -->
                <CheckBox Content="IsActive" Click="CheckBox_Click" Tag="{Binding DpData}"/>
            </GridViewColumn>
        </GridView>
    </ListView.View>
</ListView>
// This method could be used for all columns,
// as long as they contain the necessary info
// which should be provided in the XAML:
//     - Item Collection
//     - Property Name
private void CheckBox_Click(object sender, RoutedEventArgs e)
{
    var cb = sender as CheckBox;
    var items = cb.Tag as IEnumerable;
    PropertyInfo prop = null;
    foreach (var item in items)
    {
        if (prop == null)
        {
            var type = item.GetType();
            var propname = cb.Content as string;
            prop = type.GetProperty(propname);
        }
        prop.SetValue(item, cb.IsChecked, null);
    }
}

答案 2 :(得分:0)

如果你想坚持使用MVVM方法,我建议采用绑定方法而不是事件处理方法,因为MVVM避免在代码隐藏文件中编写代码。

一种方法是简单地在视图模型中绑定两个bool属性,并使用IsChecked两个复选框的属性。根据使用INotifyPropetyChanged的更改通知,您可以遍历您的itemssource即AveragingParameters并更改CalMinCalcAverage