通过单击复选框获取listbox.selectedindex

时间:2015-04-25 13:58:08

标签: c# wpf checkbox listbox wpf-controls

这是我在列表框中的用户模板。我想点击列表框的任何复选框都有“listbox.selectedindex”。我想知道选中哪一行,复选框。在复选框的点击事件中,它应该聚焦整个选定的行。

   <ListView x:Name="listbox3"  Visibility="Visible" Margin="540,168,37,46" IsSynchronizedWithCurrentItem="True" BorderBrush="Black">
        <ListView.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal" Width="200" >

                    <TextBlock Text="{Binding VmName}" Width="129" Visibility="Visible" />
                    <CheckBox  x:Name="cb" IsThreeState="False"   IsChecked="{Binding IsCheck, Mode=TwoWay}"  Margin="6,0,18,6" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
                    <CheckBox  x:Name="cb1" IsThreeState="False"  IsChecked="{Binding IsCheck1, Mode=TwoWay}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"  />

                </StackPanel>
            </DataTemplate>

        </ListView.ItemTemplate>
    </ListView>

enter image description here

1 个答案:

答案 0 :(得分:1)

如果没有明确说明问题的a good, minimal, complete code example,很难确切地知道哪些建议对您最有用。如果没有a clear problem statement,你甚至不清楚你希望代码做什么。

但是,如果我理解正确,您将使用DataTemplate中相应的ListView对象显示某些数据项类型。用户可以切换复选框,并且您想要更新ListView中当前选定的项目,以便它始终是包含刚刚切换的复选框的项目。

至少有几种合理的方法可以做到这一点。在这两种情况下,您只需将ListView.SelectedValue属性设置为与正在修改的CheckBox对应的数据项对象引用。


第一种方法是处理Checked控件本身上的UncheckedCheckBox事件,跟踪回ListViewItem,然后获取ListViewItem的数据项

首先,您需要编写一个处理程序来执行上述操作:

private void cb_Checked(object sender, RoutedEventArgs e)
{
    ListViewItem listViewItem =
       GetVisualAncestor<ListViewItem>((DependencyObject)sender);

    listbox3.SelectedValue =
        listbox3.ItemContainerGenerator.ItemFromContainer(listViewItem);
}

private static T GetVisualAncestor<T>(DependencyObject o) where T : DependencyObject
{
    do
    {
        o = VisualTreeHelper.GetParent(o);
    } while (o != null && !typeof(T).IsAssignableFrom(o.GetType()));

    return (T)o;
}

请注意辅助方法GetVisualAncestor<T>()。它使用VisualTreeHelper将树移回包含受影响的ListViewItem控件的CheckBox对象。

找到此对象后,代码会调用ItemContainerGenerator.ItemFromContainer()来查找实际的数据项对象引用,并将此引用分配给SelectedValue属性。

当然,要使处理程序有用,您需要将其订阅到相关的CheckedUnchecked事件。例如:

<DataTemplate DataType="{x:Type local:DataItem}">
  <StackPanel Orientation="Horizontal" Width="200" >
    <TextBlock Text="{Binding VmName}" Width="129" Visibility="Visible" />
    <CheckBox  x:Name="cb" IsThreeState="False"
               IsChecked="{Binding IsChecked1, Mode=TwoWay}" 
               Margin="6,0,18,6"
               HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
               Checked="cb_Checked" Unchecked="cb_Checked"/>
    <CheckBox  x:Name="cb1" IsThreeState="False"
               IsChecked="{Binding IsChecked2, Mode=TwoWay}"
               HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
               Checked="cb_Checked" Unchecked="cb_Checked"/>
  </StackPanel>
</DataTemplate>

(由于你没有提供一个完整的代码示例,其中包含了数据项对象类,我只根据你的问题编写了自己的代码。我更改了属性名称,使它们更有意义,即{{ 1}}和IsChecked1。请随意使用您自己的属性名称:))。


第二种方式在一方面更直接,但在另一方面稍微不那么直接。也就是说,假设您的数据项对象类实现IsChecked2,您可以为每个数据项对象订阅INotifyPropertyChanged事件,并简单地将事件的PropertyChanged指定为{{1}属性。

这更直接,因为您不必添加将可视树移回某个控件的父级的代码。但它也不那么直接,因为您需要将必要的事件处理程序附加到每个数据项对象的代码。

一个例子可能如下所示:

sender

请注意,在上面的示例中,我在任何属性更改上分配ListView.SelectedValue属性。在我自己的代码示例中,这很好,因为可以更改的唯一属性是与复选框相关的属性。当然,如果要在任何属性值更改上选择相应的List<DataItem> dataItems = new List<DataItem> { new DataItem { VmName = "sagar" }, new DataItem { VmName = "kaustubh" }, new DataItem { VmName = "gaurav" }, new DataItem { VmName = "abhi" }, }; listbox3.ItemsSource = dataItems; PropertyChangedEventHandler handler = (sender, e) => listbox3.SelectedValue = sender; foreach (DataItem item in dataItems) { item.PropertyChanged += handler; } 项,这也可以。但是,如果您真的只想更新SelectedValueListView属性的更改,则需要查看处理程序中的属性名称。 E.g:

IsChecked1


以下是我为上述两种方法的代码示例编写的IsChecked2类:

PropertyChangedEventHandler handler = (sender, e) =>
{
    if (e.PropertyName == "IsChecked1" || e.PropertyName == "IsChecked2")
    {
        listbox3.SelectedValue = sender;
    }
}