WPF 列表框不重绘

发布于 2024-07-22 04:49:05 字数 1371 浏览 3 评论 0原文

我在 XAML 中定义了一个列表框:

<ListBox x:Name="directoryList"
                 MinHeight="100" 
                 Grid.Row="0"
                 ItemsSource="{Binding Path=SelectedDirectories}"/>

SelectedDirectories 是列表 DataContext 类型 List 上的一个属性 作为

列表框数据上下文的类实现了 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));
            }
        }
    }

I have a listbox defined in XAML as:

<ListBox x:Name="directoryList"
                 MinHeight="100" 
                 Grid.Row="0"
                 ItemsSource="{Binding Path=SelectedDirectories}"/>

The SelectedDirectories is a property on the lists DataContext of type List<DirectoryInfo>

The class which is the datacontext for the listbox implements INotifyPropertyChanged. When the collection changes the items are added successfully to the list however the display does not update until I force the listbox to redraw by resizing it.

Any ideas why?

EDIT: INotifyPropertyChanged implementation

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));
            }
        }
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

吻风 2024-07-29 04:49:05

尝试

ObservableCollection<DirectoryInfo> 

相反 - 您无缘无故地触发整个列表框的刷新,并且您不需要使您的托管类实现 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 就知道要动态添加/删除什么。

Try

ObservableCollection<DirectoryInfo> 

instead - you're triggering a refresh of the entire ListBox for no reason, and you don't need to make your hosting class implement INotifyPropertyChanged - it could easily just be a property of the window. The key is to never set the property to a new instance. So:

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));
    }
}

If you end up using that FileScanner class, you need to implement INotifyCollectionChanged instead - that way, the ListBox knows what to add/remove dynamically.

街道布景 2024-07-29 04:49:05

(请参阅下面的更新)。 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 (它为您实现 INotifyCollectionChanged)。 一直更改所有签名以返回此类型,而不是 List
  • FileScanner 和 FileScannerPresenter 本身不必实现任何 INotifyXXX 接口。

    // 在 FileScanner 类 def 中          
        公共 ObservableCollection;   目录 
        { 
           得到 
           { 返回_DirList;   } 
        } 
        内部无效AddDirectory(字符串路径) 
        { 
           _路径=路径; 
           //var newItems = Directory.GetDirectories(_path).Select(thePath => new DirectoryInfo(thePath)).ToList(); 
           //_DirList.Concat( newItems );   ——由于某种原因不起作用。 
           foreach (Directory.GetDirectories(_path).Select(thePath => new DirectoryInfo(thePath)).ToList() 中的 var info 
           { 
              _DirList.Add(信息); 
           } 
        } 
      

(See Update below). WPF seems to be working alright. I put your code into a new project. The listbox updates whenever I click the button to invoke AddDirectory. You should not need any more code changes.
The problem seems to be something else.. Are there multiple threads in your UI?

I didnt have the FileScanner type. So I created a dummy as follows.

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;      }
   }

No changes to your FileScannerPresenter class. Or your listbox XAML. I created a Window with a DockPanel containing your listbox, a textbox and a button.

Update: Paul Betts is right. It works because I return a new list each time from the Bound property. Data binding with lists always messes me up.
With more tinkering, the easy way to do this is:

  • Make FileScanner#Directories return an ObservableCollection<DirectoryInfo> (which implements INotifyCollectionChanged for you). Change all signatures all the way up to return this type instead of a List<DirectoryInfo>
  • FileScanner and FileScannerPresenter themselves do not have to implement any INotifyXXX interface.

    //  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);
         }
      }
    
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文