Список WPF не перерисовывается
Вопрос
У меня есть список, определенный в XAML как:
<ListBox x:Name="directoryList"
MinHeight="100"
Grid.Row="0"
ItemsSource="{Binding Path=SelectedDirectories}"/>
SelectedDirectories — это свойство в списках DataContext типа List<DirectoryInfo>
Класс, который является контекстом данных для списка, реализует INotifyPropertyChanged.Когда коллекция изменяется, элементы успешно добавляются в список, однако отображение не обновляется, пока я не заставлю список перерисоваться, изменив его размер.
Есть идеи, почему?
РЕДАКТИРОВАТЬ:Реализация INotifyPropertyChanged
public class FileScannerPresenter : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private FileScanner _FileScanner;
public FileScannerPresenter()
{
this._FileScanner = new FileScanner();
}
public List<DirectoryInfo> SelectedDirectories
{
get
{
return _FileScanner.Directories;
}
}
public void AddDirectory(string path)
{
this._FileScanner.AddDirectory(path);
OnPropertyChanged("SelectedDirectories");
}
public void OnPropertyChanged(string property)
{
if (this.PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
Решение
Пытаться
ObservableCollection<DirectoryInfo>
вместо этого вы запускаете обновление всего ListBox без причины, и вам не нужно, чтобы ваш хост-класс реализовывал INotifyPropertyChanged — это легко может быть просто свойством окна.Главное — никогда не устанавливать свойство для нового экземпляра.Так:
class SomeWindow : Window {
public ObservableCollection<DirectoryInfo> SelectedDirectories {get; private set;}
SomeWindow() { SelectedDirectories = new ObservableCollection<DirectoryInfo>(); }
public void AddDirectory(string path) {
SelectedDirectories.Add(new DirectoryInfo(path));
}
}
Если вы в конечном итоге будете использовать этот класс FileScanner, вам необходимо вместо этого реализовать INotifyCollectionChanged - таким образом ListBox будет знать, что добавлять/удалять динамически.
Другие советы
(См. Обновление ниже).WPF, кажется, работает нормально.Я поместил ваш код в новый проект. Список обновляется всякий раз, когда я нажимаю кнопку для вызова AddDirectory.Вам больше не потребуется вносить изменения в код. Проблема видимо в другом..Есть ли в вашем пользовательском интерфейсе несколько потоков?
У меня не было типа FileScanner.Поэтому я создал манекен следующим образом.
public class FileScanner
{
string _path;
public FileScanner()
{ _path = @"c:\"; }
public List<DirectoryInfo> Directories
{
get
{
return Directory.GetDirectories(_path).Select(path => new DirectoryInfo(path)).ToList();
}
}
internal void AddDirectory(string path)
{ _path = path; }
}
Никаких изменений в вашем классе FileScannerPresenter.Или ваш список XAML.Я создал окно с DockPanel, содержащим ваш список, текстовое поле и кнопку.
Обновлять: Пол Беттс прав.Это работает, потому что я каждый раз возвращаю новый список из свойства Bound.Привязка данных со списками всегда меня смущает.Если повозиться, простой способ сделать это:
- Заставить FileScanner#Directories возвращать
ObservableCollection<DirectoryInfo>
(который реализуетINotifyCollectionChanged
для тебя).Измените все подписи до конца, чтобы они возвращали этот тип вместоList<DirectoryInfo>
FileScanner и FileScannerPresenter не обязательно должны реализовывать какой-либо интерфейс INotifyXXX.
// in FileScanner class def public ObservableCollection<DirectoryInfo> Directories { get { return _DirList; } } internal void AddDirectory(string path) { _path = path; //var newItems = Directory.GetDirectories(_path).Select(thePath => new DirectoryInfo(thePath)).ToList(); //_DirList.Concat( newItems ); -- doesn't work for some reason. foreach (var info in Directory.GetDirectories(_path).Select(thePath => new DirectoryInfo(thePath)).ToList()) { _DirList.Add(info); } }