将 CheckBox IsChecked 属性 绑定到 ListView 的 SelectedItems 属性

Binding the CheckBox IsChecked Property to SelectedItems Property of a ListView

我在 MVVM 数据绑定方面遇到困难。

在我的示例中,我有一个 ListView 填充的项目,其中包含 CheckBox 和一些其他内容。

<ListView 
   Background="#f0f0f0" 
   Grid.Row="1" 
   ItemsSource="{Binding ListViewCollection}" 
   SelectedItem="{Binding SelectedItem}" 
   IsSynchronizedWithCurrentItem="True" 
   BorderThickness="0" 
   Margin="5">
   <ListView.View>
      <GridView>
         <GridView.Columns>
            <GridViewColumn>
               <GridViewColumn.CellTemplate>
                  <DataTemplate>
                     <CheckBox  Tag="{Binding TheValue}" IsChecked="{Binding IsChecked}" />
                  </DataTemplate>
               </GridViewColumn.CellTemplate>
            </GridViewColumn>
            <GridViewColumn DisplayMemberBinding="{Binding TheText}" Header="#Cell" />
            <GridViewColumn DisplayMemberBinding="{Binding TheVoltage}" Header="U[V]" />
         </GridView.Columns>
      </GridView>
   </ListView.View>
</ListView>

ListViewItemSource 绑定到 ViewModel 中数据 class 的 ObservableCollection,就像您在 MVVM 中所做的那样。

现在我想将每个列表视图项的 Checkbox.IsChecked 属性 连接到父级 ListView.SelectedItems 属性 以触发它。为什么?因为我要show/hide一系列的数据图。因此,如果选中第一行中的 CheckBox,则显示图表 1。如果未选中第二行中的 CheckBox,则隐藏图表 2,依此类推。像这样:

public ListViewItem SelectedItem
    {
        get { return mSelectedItem; }
        set
        {
            if (mSelectedItem!= value)
            {
                mSelectedItem= value;
                RaisePropertyChanged("SelectedItem");
                if (SelectedItem.IsChecked == true)
                {
                    OxyplotModel.Series[1].IsVisible = false;
                    OxyplotModel.InvalidatePlot(true);
                }
            }
        }
    }

要触发此 属性,您必须在 GUI 中单击两次。首先选中 CheckBox,然后再次单击该行以触发并隐藏图表。但我想在点击 CheckBox 后立即触发 SelectedItems 属性。

至此,我给CheckBox绑定了一个命令,并传递了一个参数来区分复选框。但正如我所说,我想使用 属性.

这是否可能或有更好的想法来解决我的问题?

所选项目将是绑定到项目源的项目类型。如果项目来源是列表意味着选择的项目将是学生。

据我了解,您的问题是由 CheckBoxListViewItem 窃取焦点造成的。如果你想在 CheckBox 被点击时 select 项目,你可以使用当 ListViewItem 中的某些东西获得焦点时触发的动画,这会将 IsSelected 设置为 true

<ListView ... 
   ItemsSource="{Binding ListViewCollection}" 
   SelectedItem="{Binding SelectedItem}" 
   SelectionMode="Single">
   <ListView.View>
       <!-- removed -->
   </ListView.View>
   <ListView.ItemContainerStyle>
      <Style TargetType="{x:Type ListViewItem}">
         <Style.Triggers>
            <EventTrigger RoutedEvent="GotKeyboardFocus">
               <BeginStoryboard>
                  <Storyboard>
                     <BooleanAnimationUsingKeyFrames BeginTime="0:0:0" Duration="0:0:0" Storyboard.TargetProperty="IsSelected">
                        <DiscreteBooleanKeyFrame Value="True" />
                     </BooleanAnimationUsingKeyFrames>
                  </Storyboard>
               </BeginStoryboard>
            </EventTrigger>
         </Style.Triggers>
      </Style>
   </ListView.ItemContainerStyle>
</ListView>

您还需要指定 SelectionMode="Single" 否则之前的项目将不会被取消selected

编辑

它向项目容器样式 (ListViewItem) 添加了新的事件触发器,只要 GotKeyboardFocus event occurs. It's bubbling event meaning it will bubble up the visual tree from any ListViewItem child and finally reach ListViewItem where it will trigger BooleanAnimationUsingKeyFrames 能够更改 Boolean 属性值的动画就会执行。在这种情况下,它不是真正的动画,因为它需要 0 秒,但它会将 IsSelected 属性(由 Storyboard.TargetProperty 指定)设置为 true

我想 post 使用 Command 和 CommandParameter 实现此解决方案的替代方法。

在您的 XAML 中将命令绑定到复选框。还将 CommandParameter 绑定到将传递给命令本身的值。请注意:因为 ListView 的 ItemSource 设置为 Observablecollection,所以您必须使用

更改为父 DataContext

Command="{Binding ElementName=NameOfListView,Path=DataContext.NameOfCommand}"

从 ViewModel DataContext 绑定命令。您也可以使用 Ancestor 来获取父数据上下文。

<ListView
   Background="#f0f0f0" 
   Grid.Row="1" 
   ItemsSource="{Binding ListViewCollection}" 
   Name="ListView" 
   IsSynchronizedWithCurrentItem="True" 
   BorderThickness="0" 
   Margin="5">
   <ListView.View>
      <GridView>
         <GridView.Columns>
            <GridViewColumn>
               <GridViewColumn.CellTemplate>
                  <DataTemplate>
                      <CheckBox IsChecked="{Binding IsChecked}" 
                      Command="{Binding ElementName=ListView,Path=DataContext.HideShowGraph}" 
                      CommandParameter="{Binding TheValue, Mode=OneWay}" />
                  </DataTemplate>
               </GridViewColumn.CellTemplate>
            </GridViewColumn>
            <GridViewColumn DisplayMemberBinding="{Binding TheText}" Header="#Cell" />
            <GridViewColumn DisplayMemberBinding="{Binding TheVoltage}" Header="U[V]" />
         </GridView.Columns>
      </GridView>
   </ListView.View>
</ListView>

然后在您的 ViewModel 中声明一个带参数的 RelayCommand 和相应的委托方法。

public class ViewModel : ViewModelBase
    {
        public ViewModel()
        {
            HideShowGraph = new RelayCommand<int>(foo => HideShowGraphExecute(foo));
        }

        public ICommand HideShowGraph { get; private set; }

        private void HideShowGraphExecute(int foo)
        {
           //...evaluate foo
        }
    }

因此,如果选中 ListView 中的一个 Checkbox,则会调用 Command 并将 CommandParameter 的有界值(在此示例中 "TheValue")传递给委托方法 HideShowGraphExecute。使用此值,您可以区分复选框。

希望对您也有帮助!