【问题标题】:Binding the CheckBox IsChecked Property to SelectedItems Property of a ListView将 CheckBox IsChecked 属性绑定到 ListView 的 SelectedItems 属性
【发布时间】:2015-07-24 09:47:52
【问题描述】:

我在处理 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 中数据类的 ObservableCollection,就像在 MVVM 中一样。

现在我想将每个列表视图项的Checkbox.IsChecked 属性连接到父级ListView.SelectedItems 属性以触发它。为什么?因为我想显示/隐藏一系列数据图。因此,如果选中第一行中的 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 并传递一个参数来区分复选框。但正如我所说,我想使用该属性。

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

【问题讨论】:

  • 当您使用绑定时,ListView.SelectedItem 不会是 ListViewItem 类型。它只是一个容器。它将与您的收藏中的项目具有相同的类型。因此,如果 ItemsSource 绑定到 List&lt;MyItemClass&gt;ListView.SelectedItem(s) 将给出 MyItemClass 这应该是您绑定属性的类型
  • 是的,我知道!但这不是我的问题。 SelectedItem 仅在单击行时触发,而不是在复选框上!我知道我必须将一个属性绑定到与 ItemSource 相同类型的 SelectedItem。我很清楚!
  • 我知道这不是你的问题,因此只发表评论。据我了解,您的问题是 ListViewItem 未被选中,因为 CheckBox 获得焦点。是否希望在单击 CheckBox 时选中 ListViewItem
  • 没错,这就是我想要的!!
  • 我之前问过一个非常相似的问题,我认为我得到的解决方案比你得到的当前答案更简单stackoverflow.com/questions/15091716/…

标签: c# wpf listview mvvm data-binding


【解决方案1】:

据我了解您的问题是由CheckBoxListViewItem 窃取焦点引起的。如果您想在单击 CheckBox 时选择项目,您可以使用在 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" 否则上一项不会被取消选择

编辑

它为项目容器样式(ListViewItem)添加了新的事件触发器,每当GotKeyboardFocus 事件发生时都会执行。它是bubbling event,这意味着它将从任何ListViewItem 子级中冒出视觉树并最终到达ListViewItem,在那里它将触发BooleanAnimationUsingKeyFrames 动画,该动画能够更改Boolean 属性的值。在这种情况下,它并不是真正的动画,因为它需要 0 秒,但它会将 IsSelected 属性(由 Storyboard.TargetProperty 指定)设置为 true

【讨论】:

  • 嘿 dkozi 非常感谢你。这就是解决方案。也许你可以解释一下这些 xmal 标签在做什么。好的,我有解决方案,但我不明白。
【解决方案2】:

选定的项目将是绑定到项目源的项目的类型。如果项目来源是列表,则表示选定项目将为学生。

【讨论】:

  • 您能否在回答中添加更多详细信息。我不确定这是否足以解决问题,尽管它似乎指向了正确的方向。
【解决方案3】:

我想发布一个替代方案,以使用 Command 和 CommandParameter 实现此解决方案。

在您的 XAML 中将命令绑定到复选框。还将 CommandParameter 绑定到将传递给 Command 本身的值。请注意:由于 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 中的一个复选框,则会调用 Command 并将 CommandParameter 的有界值(在此示例中为“TheValue”)传递给委托方法 HideShowGraphExecute。使用此值,您可以区分复选框。

希望它也有帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-15
    • 2016-04-26
    • 1970-01-01
    • 2011-02-24
    • 1970-01-01
    • 2012-03-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多