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

时间:2013-12-10 16:37:28

标签: 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.OriginalSource as FrameworkElement).DataContext;
                var lbi = LstDistro.ItemContainerGenerator.ContainerFromItem(clicked) as ListBoxItem;
                lbi.IsSelected = true;
            }

现在我试图以另一种方式做到这一点。每当选择ListBoxItem时,其中的复选框都会被勾选。到目前为止,我已经拥有了它,因此您选择的第一个项目将被勾选,但在此之后,您选择的其他任何项目都不会被勾选。我需要以某种方式让它遍历所有当前选定的项目。

我目前的代码:

WPF:

<ListBox x:Name="LstDistro" HorizontalAlignment="Left" Margin="10,10,0,42" Width="235" BorderBrush="Black" BorderThickness="2,2,1,1" SelectionMode="Multiple" SelectionChanged="LstDistro_SelectionChanged">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <Canvas x:Name="EventItem" HorizontalAlignment="Left" Height="42" VerticalAlignment="Top" Width="215" Background="{Binding Path=LBackground}">
                            <Label Content="{Binding LInits}" HorizontalAlignment="Left" Height="33" VerticalAlignment="Top" Width="40" FontWeight="Bold" FontSize="12" Canvas.Top="5"/>
                            <Label Content="{Binding LFullName}" HorizontalAlignment="Left" Height="33" VerticalAlignment="Top" Width="164" FontSize="12" Canvas.Left="40" Canvas.Top="5"/>
                            <CheckBox x:Name="ChkName" Height="20" Width="20" Canvas.Left="190" Canvas.Top="12" Checked="CheckBox_Checked"  IsChecked="False"/>
                        </Canvas>
                    </Grid>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

C#:

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

            private void LstDistro_SelectionChanged(object sender, SelectionChangedEventArgs e)
            {

                //Get the current selected item
                ListBoxItem item = LstDistro.ItemContainerGenerator.ContainerFromIndex(LstDistro.SelectedIndex) as ListBoxItem;
                CheckBox ChkName = null;

                //Get the item's template parent
                ContentPresenter templateParent = GetFrameworkElementByName<ContentPresenter>(item);
                //Get the DataTemplate that the Checkbox is in.
                DataTemplate dataTemplate = LstDistro.ItemTemplate;
                ChkName = dataTemplate.FindName("ChkName", templateParent) as CheckBox;
                ChkName.IsChecked = true;
            }

            private static T GetFrameworkElementByName<T>(FrameworkElement referenceElement) where T : FrameworkElement
            {
                FrameworkElement child = null;
                for (Int32 i = 0; i < VisualTreeHelper.GetChildrenCount(referenceElement); i++)
                {
                    child = VisualTreeHelper.GetChild(referenceElement, i) as FrameworkElement;
                    System.Diagnostics.Debug.WriteLine(child);
                    if (child != null && child.GetType() == typeof(T))
                    { break; }
                    else if (child != null)
                    {
                        child = GetFrameworkElementByName<T>(child);
                        if (child != null && child.GetType() == typeof(T))
                        {
                            break;
                        }
                    }
                }
                return child as T;
            }

3 个答案:

答案 0 :(得分:1)

确定。删除所有代码并从头开始。

如果你正在使用WPF,你真的需要理解并接受The WPF Mentality

这就是你在正确的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>

代码背后:

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

结果:

enter image description here

  • 注意当你使用WPF的功能而不是手动,程序,类似winforms的方法时,生活是多么简单和快乐。
  • 简单,简单的属性和INotifyPropertyChanged。这就是你在WPF中编程的方式。无需复杂的VisualTreeHelper.Whatever()内容,无需在过程代码中操作UI。简单,美丽DataBinding
  • 了解我如何针对SelectAll()UnSelectAll()方法中的数据进行操作,而不是使用UI。用户界面不负责维护数据状态,仅用于显示数据。
  • 将我的代码复制并粘贴到File -> New Project -> WPF Application中,然后自行查看结果。
  • WPF Rocks

答案 1 :(得分:1)

请参阅VisualHelper class here

它提供了FindVisualChild,FindVisualChilds

的扩展方法
var checkedCheckBoxes= LstDistro.FindVisualChilds<CheckBox>().Where(s=>s.IsChecked==true);

答案 2 :(得分:1)

您应该像这样设置Checkbox IsChecked绑定:

IsChecked="{Binding Path=IsSelected, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}}"

这意味着每当您选择ListBoxItem时,您的复选框也将被选中。

希望这有助于:)