Как установить CheckBox.IsChecked в зависимости от наличия связанного объекта в списке - PullRequest
5 голосов
/ 03 февраля 2011

Есть 2 списка - AvailableItems и SelectedItems.

AvailableItems отображается в ListBox, и каждый ListBoxItem содержит CheckBox. Предполагается, что CheckBox проверяется, если связанный элемент находится в SelectedItems.

Могу ли я добиться этого без обработки Checked и Unchecked в выделенном фрагменте кода и без добавления свойства IsSelected в мой класс элементов?

Вот XAML:

   <ListBox Name="ListBox1" ItemsSource="{Binding Path=AvailableItems}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel></StackPanel>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <DockPanel>
                    <CheckBox Name="cb1"></CheckBox>
                    <TextBlock Text="{Binding}"></TextBlock>
                </DockPanel>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ListBox>

и код:

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            _availableItems.Add(Colors.Red);
            _availableItems.Add(Colors.Green);
            _availableItems.Add(Colors.Blue);

            _selectedItems.Add(Colors.Green);

            this.DataContext = this;
        }

        ObservableCollection<Color> _selectedItems = new ObservableCollection<Color>();
        public ObservableCollection<Color> SelectedItems
        {
            get { return _selectedItems; }
            set { _selectedItems = value; }
        }

        ObservableCollection<Color> _availableItems = new ObservableCollection<Color>();
        public ObservableCollection<Color> AvailableItems
        {
            get { return _availableItems; }
            set { _availableItems = value; }
        }
    }

Приведенный выше xaml / code можно скопировать прямо в новый проект WPF для тестирования.

Ответы [ 2 ]

3 голосов
/ 03 февраля 2011

Вы определяете конвертер нескольких значений, который берет элемент и коллекцию и возвращает логическое значение:

public class CollectionContainsConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var item = values[0];
        var collection = values[1] as IList;
        return collection.Contains(item);
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

, а затем используете его следующим образом:

    <ListBox Name="ListBox1" ItemsSource="{Binding Path=AvailableItems}">
        <ListBox.Resources>
            <local:CollectionContainsConverter x:Key="contains"/>
        </ListBox.Resources>
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel></StackPanel>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <DockPanel>
                    <CheckBox Name="cb1">
                        <CheckBox.IsChecked>
                            <MultiBinding Converter="{StaticResource contains}" Mode="OneWay">
                                <Binding Mode="OneWay"/>
                                <Binding ElementName="ListBox1" Path="DataContext.SelectedItems" Mode="OneWay"/>
                            </MultiBinding>
                        </CheckBox.IsChecked>
                    </CheckBox>
                    <TextBlock Text="{Binding}"></TextBlock>
                </DockPanel>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ListBox>

Обработка обратногопреобразование оставлено в качестве упражнения.

0 голосов
/ 03 февраля 2011

Грубый макет с использованием MVVM

создайте класс для представления всех данных, необходимых для каждого элемента, например, Проверено и описание

class CustomItem : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private bool _isSelected;
        private string _customColour;

        public bool IsSelected
        {
            get { return _isSelected; }
            set 
            { 
                _isSelected = value;
                if (PropertyChanged != null)
                {
                    PropertyChanged.Invoke(this, new PropertyChangedEventArgs("IsSelected"));
                }
            }
        }

        public string CustomColour
        {
            get { return _customColour; }
            set
            {
                _customColour = value;
                if (PropertyChanged != null)
                {
                    PropertyChanged.Invoke(this, new PropertyChangedEventArgs("CustomColour"));
                }
            }
        }        
    }

создать класс для представления коллекции элементов, которую вы хотите отобразить

   class CustomItems : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        private ObservableCollection<CustomItem> _listOfCustomItems;

        public CustomItems()
        {
            ListOfCustomItems = new ObservableCollection<CustomItem>();

            var c = new CustomItem
                        {
                            IsSelected = false, 
                            CustomColour = "Red"
                        };
            ListOfCustomItems.Add(c); 

            c = new CustomItem
                    {
                        IsSelected = true, 
                        CustomColour = "Green"
                    };
            ListOfCustomItems.Add(c);

            c = new CustomItem
                    {
                        IsSelected = false, 
                        CustomColour = "Blue"
                    };

            ListOfCustomItems.Add(c);
        }

        public ObservableCollection<CustomItem> ListOfCustomItems
        {
            get { return _listOfCustomItems; }
            set 
            { 
                _listOfCustomItems = value;
                if (PropertyChanged != null)
                {
                    PropertyChanged.Invoke(this, new PropertyChangedEventArgs("ListOfCustomItems"));
                }
            }
        }

        public List<CustomItem> SelectedItems
        {
            get
            {
                return (from customItem in ListOfCustomItems 
                        where customItem.IsSelected 
                        select customItem).ToList();
            }
        }
    }

Добавить в окно

 <Window.Resources>
        <WpfApplication1:CustomItems x:Key="CI"/>
    </Window.Resources>
    <Grid DataContext="{StaticResource CI}">
        <ListBox ItemsSource="{Binding Path=ListOfCustomItems}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel></StackPanel>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <DockPanel>
                        <CheckBox IsChecked="{Binding Path=IsSelected}"/>
                        <TextBlock Text="{Binding Path=CustomColour}"/>
                    </DockPanel>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ListBox>
    </Grid>

Вы ведете единый список элементов и предоставляете свойство для получения выбранных элементов, которое выполняет простой выбор LINQ. Легко. Измените типы данных по мере необходимости.

...