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

getting listbox.selectedindex by clicking on checkbox

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

   <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>

如果没有 a good, minimal, complete code example that clearly illustrates the problem, it is difficult to know exactly what advice would be most useful to you. Without a clear problem statement,甚至不完全清楚您希望代码做什么。

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

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


第一种方法涉及处理 CheckBox 控件本身上的 CheckedUnchecked 事件,跟踪回 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 将树走回包含受影响的 CheckBox 控件的 ListViewItem 对象。

找到此对象后,代码会调用 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>

(由于您没有提供完整的代码示例,其中包含数据项对象 class,我只是根据您的问题编写了自己的代码示例。我更改了 属性 名称这样它们就更有意义了,即 IsChecked1IsChecked2。请随意使用您自己的 属性 名称:)).


第二种方式一方面更直接一点,另一方面又不那么直接。也就是说,假设您的数据项对象 class 实现了 INotifyPropertyChanged,您可以为每个数据项对象订阅 PropertyChanged 事件,并简单地将事件的 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;
}

请注意,在上面的示例中,我将 SelectedValue 属性 分配给 any 属性 更改。在我自己的代码示例中,这很好,因为唯一可以更改的属性是与复选框相关的属性。当然,如果您想在任何 属性 值更改时 select 相应的 ListView 项目,这也很好。但是,如果您真的只想更新 IsChecked1IsChecked2 属性的更改,则需要查看处理程序中的 属性 名称。例如:

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


这是我为上述两种方法编写的代码示例 DataItem class:

class DataItem : INotifyPropertyChanged
{
    private string _vmName;
    private bool _isChecked1;
    private bool _isChecked2;

    public string VmName
    {
        get { return _vmName; }
        set { _vmName = value; OnPropertyChanged(); }
    }

    public bool IsChecked1
    {
        get { return _isChecked1; }
        set { _isChecked1 = value; OnPropertyChanged(); }
    }

    public bool IsChecked2
    {
        get { return _isChecked2; }
        set { _isChecked2 = value; OnPropertyChanged(); }
    }

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;

        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
}