Подтвердить что ты не робот

Как реализовать ListBox флажков в WPF?

Несмотря на то, что он несколько опытен при написании приложений Winforms,... "неопределенность" WPF по-прежнему ускользает от лучших практик и шаблонов проектирования.

Несмотря на заполнение моего списка во время выполнения, мой список выглядит пустым.

Я выполнил простые инструкции из этой полезной статьи безрезультатно. Я подозреваю, что мне не хватает какого-то метода DataBind(), где я рассказываю списку, что я сделал, изменяя базовый список.

В моем MainWindow.xaml у меня есть:

    <ListBox ItemsSource="{Binding TopicList}" Height="177" HorizontalAlignment="Left" Margin="15,173,0,0" Name="listTopics" VerticalAlignment="Top" Width="236" Background="#0B000000">
        <ListBox.ItemTemplate>
            <HierarchicalDataTemplate>
                <CheckBox Content="{Binding Name}" IsChecked="{Binding IsChecked}"/>
            </HierarchicalDataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

В моем коде, у меня есть:

    private void InitializeTopicList( MyDataContext context )
    {
        List<Topic> topicList = ( from topic in context.Topics select topic ).ToList();

        foreach ( Topic topic in topicList )
        {
            CheckedListItem item = new CheckedListItem();
            item.Name = topic.DisplayName;
            item.ID = topic.ID;
            TopicList.Add( item );
        }
    }

Что, прослеживая, я знаю, что заселено четырьмя элементами.

ИЗМЕНИТЬ

Я изменил TopicList на ObservableCollection. Это все еще не работает.

    public ObservableCollection<CheckedListItem> TopicList;

ИЗМЕНИТЬ № 2

Я сделал два изменения, которые помогают:

В файле .xaml:

ListBox ItemsSource="{Binding}"

В исходном коде после заполнения списка:

listTopics.DataContext = TopicList;

Я получаю список, но он не автоматически обновляет флажки, когда я их обновляю. Я подозреваю, что небольшое чтение с моей стороны разрешит это.

4b9b3361

Ответ 1

Используйте ObservableCollection<Topic> вместо List<Topic>

Edit

он реализует интерфейс INotifyCollectionChanged, чтобы WPF мог знать, когда вы добавляете/удаляете/изменяете элементы

Изменить 2

Поскольку вы устанавливаете TopicList в коде, это должно быть свойство зависимостей, а не общее поле

    public ObservableCollection<CheckedListItem> TopicList {
        get { return (ObservableCollection<CheckedListItem>)GetValue(TopicListProperty); }
        set { SetValue(TopicListProperty, value); }
    }
    public static readonly DependencyProperty TopicListProperty =
        DependencyProperty.Register("TopicList", typeof(ObservableCollection<CheckedListItem>), typeof(MainWindow), new UIPropertyMetadata(null));

Изменить 3

Чтобы увидеть изменения в элементах

  • реализовать INotifyPropertyChanged интерфейс в CheckedListItem (каждый сеттер должен вызывать событие PropertyChanged(this, new PropertyChangedEventArgs(<property name as string>)))
  • или вывести CheckedListItem из DependencyObject и преобразовать Name, ID, IsChecked в свойства зависимостей
  • или полностью обновить их (topicList[0] = new CheckedListItem() { Name = ..., ID = ... })

Ответ 2

Предполагая, что TopicList не является ObservableCollection<T>, поэтому, когда вы добавляете элементы, никакие INotifyCollection не изменяются, чтобы сообщить механизму привязки об обновлении значения.

Измените TopicList на ObservableCollection<T>, который разрешит текущую проблему. Вы также могли бы заблаговременно заполнить List<T>, а затем привязка будет работать через OneWay; однако ObservableCollection<T> является более надежным подходом.

EDIT:

Ваш TopicList должен быть свойством не переменной-членом; привязки требуют свойств. Он не должен быть DependencyProperty.

ИЗМЕНИТЬ 2:

Измените свой ItemTemplate, поскольку он не должен быть HierarchicalDataTemplate

   <ListBox.ItemTemplate>
     <DataTemplate>
       <StackPanel>
         <CheckBox Content="{Binding Name}" IsChecked="{Binding IsChecked}"/>
       </StackPanel>
     </DataTemplate>
   </ListBox.ItemTemplate>

Ответ 3

Сначала вам не нужен HeirarchicalDataTemplate для этого. Просто регулярный DataTemplate, как дал Аарон, достаточно. Затем вам нужно создать экземпляр ObjectList ObservableCollection внутри конструктора класса. что делает ObservableCollection живым даже до того, как вы добавите в него данные. И система привязки знает коллекцию. Затем, когда вы добавляете каждую тему /CheckedListItem, она будет автоматически отображаться в пользовательском интерфейсе.

TopicList = new ObservableCollection<CheckedListItem>(); //This should happen only once

private void InitializeTopicList( MyDataContext context )
{
    TopicList.Clear();

    foreach ( Topic topic in topicList )
    {
        CheckedListItem item = new CheckedListItem();
        item.Name = topic.DisplayName;
        item.ID = topic.ID;
        TopicList.Add( item );
    }
}

Ответ 4

Другие уже сделали полезные предложения (используйте наблюдаемую коллекцию, чтобы получить уведомление об изменении списка, сделайте коллекцию свойством, а не полем). Вот два из них:

1) Всякий раз, когда у вас возникает проблема с привязкой данных, посмотрите в окне "Выход", чтобы убедиться, что вы не получаете никаких ошибок привязки. Вы можете потратить много времени, пытаясь исправить неправильную проблему, если вы этого не сделаете.

2) Поймите, что уведомление об изменении роли играет в привязке. Изменения в источнике данных не могут и не будут распространяться в пользовательском интерфейсе, если источник данных не будет уведомлять об изменении. Существует два способа сделать это для нормальных свойств: сделать источник данных из DependencyObject и сделать свойство привязки зависимым свойством или сделать реализацию источника данных INotifyPropertyChanged и поднять событие PropertyChanged при изменении значения свойства, При привязке ItemsControl к коллекции используйте класс коллекции, который реализует INotifyCollectionChanged (например, ObservableCollection<T>), так что изменения в содержимом и порядке коллекции будут распространяться на связанный элемент управления. (Обратите внимание, что если вы хотите, чтобы изменения в элементах коллекции были распространены на связанные элементы управления, эти элементы также должны реализовать уведомление об изменении.)

Ответ 5

измените привязку к

 <ListBox ItemsSource="{Binding Path=TopicList}"