C# 使用多选列表框在DataTemplate中查找控件

C# 使用多选列表框在DataTemplate中查找控件,c#,wpf,visual-studio-2012,listbox,datatemplate,C#,Wpf,Visual Studio 2012,Listbox,Datatemplate,我有一个多选列表框,用户可以在其中勾选列表中的多个项目。现在我有了它,所以当勾选复选框时,它所在的ListBoxItem也会被选中: private void CheckBox_Checked(object sender, RoutedEventArgs e) { //Select the Item using the DataContext of the Button object clicked = (e

我有一个多选列表框,用户可以在其中勾选列表中的多个项目。现在我有了它,所以当勾选复选框时,它所在的ListBoxItem也会被选中:

private void CheckBox_Checked(object sender, RoutedEventArgs e)
            {
                //Select the Item using the DataContext of the Button
                object clicked = (e.OriginalSource as FrameworkElement).DataContext;
                var lbi = LstDistro.ItemContainerGenerator.ContainerFromItem(clicked) as ListBoxItem;
                lbi.IsSelected = true;
            }
现在我试着用另一种方式来做。无论何时选择ListBoxItem,都会勾选其中的复选框。到目前为止,我有它,所以你选择的第一个项目将得到勾选,但在此之后,你选择的其他项目没有得到勾选。我需要以某种方式让它在当前选定的所有项目中循环

我当前的代码:

WPF:


C#:

private void复选框\u选中(对象发送方,路由目标)
{
//使用按钮的DataContext选择项目
单击的对象=(例如,OriginalSource作为FrameworkElement);
var lbi=LstDistro.ItemContainerGenerator.ContainerFromItem(单击)作为ListBoxItem;
lbi.IsSelected=true;
}
私有void LstDistro_SelectionChanged(对象发送方,selectionchangedventargs e)
{
//获取当前选定的项目
ListBoxItem=LstDistro.ItemContainerGenerator.ContainerFromIndex(LstDistro.SelectedIndex)作为ListBoxItem;
复选框ChkName=null;
//获取项目的模板父级
ContentPresenter templateParent=GetFrameworkElementByName(项);
//获取复选框所在的数据模板。
DataTemplate DataTemplate=LstDistro.ItemTemplate;
ChkName=dataTemplate.FindName(“ChkName”,templateParent)作为复选框;
ChkName.IsChecked=true;
}
私有静态T GetFrameworkElementByName(FrameworkElement引用元素),其中T:FrameworkElement
{
FrameworkElement子元素=null;
for(Int32 i=0;i
好的。删除所有代码,重新开始

如果你在使用WPF,你真的需要理解和接受它

以下是您如何在适当的WPF中完成所需的工作:

<Window x:Class="WpfApplication14.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication14"
        Title="MainWindow" Height="350" Width="525">
    <DockPanel>
        <Button Content="Show Selected Item Count" Click="Button_Click"
                DockPanel.Dock="Top"/>

        <Button Content="Select All" Click="SelectAll"
                DockPanel.Dock="Top"/>

        <Button Content="Select All" Click="UnSelectAll"
                DockPanel.Dock="Top"/>

        <ListBox ItemsSource="{Binding}" SelectionMode="Multiple">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <CheckBox IsChecked="{Binding IsSelected}" Content="{Binding DisplayName}"/>
                </DataTemplate>
            </ListBox.ItemTemplate>

            <ListBox.ItemContainerStyle>
                <Style TargetType="ListBoxItem">
                    <Setter Property="IsSelected" Value="{Binding IsSelected}"/>
                </Style>
            </ListBox.ItemContainerStyle>
        </ListBox>
    </DockPanel>
</Window>
结果:

  • 请注意,当您使用WPF的功能而不是手动的、过程性的、类似winforms的方法时,生活是多么简单和快乐
  • 简单、简单属性和
    INotifyPropertyChanged
    。这就是在WPF中编程的方式。不需要复杂的
    VisualTreeHelper.which()
    stuff,不需要在过程代码中操作UI。简单,美丽
  • SelectAll()
    UnSelectAll()
    方法中,而不是在UI中,查看我是如何针对我的数据操作的。UI不负责维护数据的状态,只负责显示数据
  • 文件->新项目->WPF应用程序中复制并粘贴我的代码,然后自己查看结果
  • WPF岩石
参见

它提供了扩展方法FindVisualChild、FindVisualChilds

var checkedCheckBoxes= LstDistro.FindVisualChilds<CheckBox>().Where(s=>s.IsChecked==true);
var checkedcheckbox=LstDistro.FindVisualChilds()。其中(s=>s.IsChecked==true);

您应该像这样设置复选框IsChecked binding:

IsChecked="{Binding Path=IsSelected, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}}"
这意味着每当您选择ListBoxItem时,您的复选框也将被选中


希望这有帮助:)

首先非常感谢您的回答。然而,我刚刚尝试在代码中使用它,但它不起作用。所选项目和复选框之间没有链接。它所做的唯一一件事是更改了复选框主题,现在列表项“选择颜色”已从“我的绿色”变为“windows蓝色”,就像您的图片一样。@user2911340确保您的项目中没有任何其他冲突的
样式。如果您这样做,您将不得不将
ItemContainerStyle
与您自己的样式合并。我已将您提供的所有代码放在公共主窗口(){}区域之外,仍然无法看到listboxitem selected和checkbox selected之间的链接。这是我的代码隐藏:和我的wpf:
public partial class MainWindow : Window
{
    private ObservableCollection<SelectableItem> Items { get; set; } 

    public MainWindow()
    {
        InitializeComponent();

        //Create dummy items, you will not need this, it's just part of the example.
        var dummyitems = Enumerable.Range(0, 100)
                                   .Select(x => new SelectableItem()
                                   {
                                       DisplayName = x.ToString()
                                   });

        DataContext = Items = new ObservableCollection<SelectableItem>(dummyitems);
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        MessageBox.Show(Items.Count(x => x.IsSelected).ToString());
    }

    private void SelectAll(object sender, RoutedEventArgs e)
    {
        foreach (var item in Items)
            item.IsSelected = true;
    }

    private void UnSelectAll(object sender, RoutedEventArgs e)
    {
        foreach (var item in Items)
            item.IsSelected = false;
    }
}
public class SelectableItem:INotifyPropertyChanged
{
    private bool _isSelected;
    public bool IsSelected
    {
        get { return _isSelected; }
        set
        {
            _isSelected = value;
            OnPropertyChanged("IsSelected");
        }
    }

    public string DisplayName { get; set; }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}
var checkedCheckBoxes= LstDistro.FindVisualChilds<CheckBox>().Where(s=>s.IsChecked==true);
IsChecked="{Binding Path=IsSelected, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}}"