0

我在 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));
            }
        }
    }
4

2 回答 2

3

尝试

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 知道要动态添加/删除什么。

于 2009-05-26T06:26:30.007 回答
0

(见下面的更新)。WPF 似乎工作正常。我将您的代码放入一个新项目中。每当我单击按钮调用 AddDirectory 时,列表框就会更新。您应该不需要更多的代码更改。 问题似乎是其他问题。您的 UI 中是否有多个线程?

我没有 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);
         }
      }
    
于 2009-05-26T07:05:54.887 回答