【问题标题】:getting listbox.selectedindex by clicking on checkbox通过单击复选框获取 listbox.selectedindex
【发布时间】:2015-04-26 12:23:30
【问题描述】:

这是我在列表框中的用户模板。我想在单击列表框的任何复选框时拥有“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>

【问题讨论】:

  • 您可以通过转到层次结构中的Parent 控件来执行此操作。您如何使用此用户控件?
  • @AfzaalAhmadZeeshan 我已经更新了 xaml 来展示我是如何使用它的。现在我需要在复选框单击事件上找到“listbox.selectedIndex”。我该怎么做呢

标签: c# wpf checkbox listbox wpf-controls


【解决方案1】:

如果没有明确说明问题的a good, minimal, complete code example,很难确切知道哪些建议对您最有用。如果没有a clear problem statement,甚至无法完全清楚您想要代码做什么。

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

至少有几种合理的方法可以做到这一点。在这两种情况下,您只需将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&lt;T&gt;()。它使用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>

(由于您没有提供包含数据项对象类的完整代码示例,因此我只是根据您的问题编写了自己的代码示例。我更改了属性名称以使其更有意义,即@987654343 @ 和 IsChecked2。请随意使用您自己的属性名称 :) )。


第二种方式在一个方面更直接,但在另一个方面不那么直接。也就是说,假设您的数据项对象类实现了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;
}

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

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


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

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

【讨论】:

    猜你喜欢
    • 2015-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 2014-02-12
    • 2015-05-12
    • 1970-01-01
    相关资源
    最近更新 更多