Как реализовать ListBox флажков в WPF? - PullRequest
19 голосов
/ 24 декабря 2010

Несмотря на некоторый опыт написания приложений для 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;

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

Ответы [ 5 ]

8 голосов
/ 24 декабря 2010

Предполагается, что 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>
5 голосов
/ 24 декабря 2010

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

Редактировать

он реализует интерфейс 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

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

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

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

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

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

3 голосов
/ 24 декабря 2010

Во-первых, вам не нужен HeirarchicalDataTemplate для этого.Достаточно обычного DataTemplate, как дал Аарон.Затем вам нужно создать экземпляр TopicList 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 );
    }
}
0 голосов
/ 24 декабря 2010

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

 <ListBox ItemsSource="{Binding Path=TopicList}"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...