ListBox ItemsSource 的数据绑定

Data Binding for ListBox ItemsSource

我在设置自动绑定时遇到问题。

我有一个简单的 WPF 应用程序,它有两个 classes - MovieInfo(包含关于我的文件系统上的电影文件的信息)和一个 MediaScanner class returns一个List<MovieInfo>。在我的 MainWindow.xaml 中,我有一个 ListBox:

<ListBox x:Name="listBox" HorizontalAlignment="Left" Height="242" Margin="10,35,0,0" VerticalAlignment="Top" Width="237" d:ItemsSource="{Binding MovieList}"/>

另外在XAML添加到<Window ...>

Name="MainWindow1"
DataContext="{Binding ElementName=MainWindow1}"

在后面的代码中,我做了一个public 属性 of the MainWindow : Window:

public ObservableCollection<MovieInfo> MovieList { get; set; }

在构造函数中:

public MainWindow()
{
    DataContext = this;
    MovieList = new ObservableCollection<MovieInfo>();
    InitializeComponent();
    //this doesn't do anything for me
    //listBox.ItemsSource = MovieList; 
}

我有一个按钮调用:

private void button_Click(object sender, RoutedEventArgs e)
{
    var scanner = new MediaScanner();
    MovieList = new ObservableCollection<MovieInfo>(scanner.ScanAll().OrderBy(x => x.Title));
    //listBox.ItemsSource = MovieList;
    
}

据我了解,这应该可以解决所有问题,但 ListBox 不会填充,除非我取消注释 button_Click 中的 listBox.ItemsSource = MovieList;。[=23] =]

我错过了什么?

ListBox 在 运行 时没有绑定 MovieList because you prefixed ItemsSource with d

After adding the namespaces, you can put d: in front of any attribute or control to show it only in the XAML Designer but not at runtime. [...]

You can use d: with attributes for any UWP or WPF .NET Core control, like colors, font sizes, and spacing. You can even add it to the control itself.

这些名称空间是在您的 XAML 根元素上定义的。

xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"

为了使绑定在 运行 时生效,删除 d: 或添加另一个 ItemsSource 而不带 d: 前缀,以便您有不同的来源设计和 运行时间。

<ListBox x:Name="listBox" HorizontalAlignment="Left" Height="242" Margin="10,35,0,0" VerticalAlignment="Top" Width="237" ItemsSource="{Binding MovieList}"/>
<ListBox x:Name="listBox" HorizontalAlignment="Left" Height="242" Margin="10,35,0,0" VerticalAlignment="Top" Width="237" d:ItemsSource="{Binding DesignTimeMovieList}" ItemsSource="{Binding MovieList}"/>

另一个问题是您既没有实现 dependency property for your movie list collection nor INotifyPropertyChanged。实际上,这意味着虽然您在按钮单击事件处理程序中将新集合分配给 MovieList 属性,但绑定不会收到更改通知,并且仍将使用旧集合实例。当然 listBox.ItemsSource = MovieList; 可以在这里工作,但是它直接分配集合并覆盖绑定,所以这是一个不同的解决方案。

在长 运行 中,您可能应该应用 MVVM 模式并将要绑定的数据分离到实现 INotifyPropertyChanged 的视图模型中,这解决了您的问题,同时分离了然后通过绑定连接您的视图和您的逻辑和数据。


您的 window.

的依赖性示例 属性
public partial class MainWindow : Window
{
   public ObservableCollection<MovieInfo> MovieList
   {
      get => (ObservableCollection<MovieInfo>)GetValue(MovieListProperty);
      set => SetValue(MovieListProperty, value);
   }

   public static readonly DependencyProperty MovieListProperty = DependencyProperty.Register(
      nameof(MovieList), typeof(ObservableCollection<MovieInfo>), typeof(MainWindow), new PropertyMetadata(null));

   public MainWindow()
   {
      DataContext = this;
      MovieList = new ObservableCollection<MovieInfo>();
      InitializeComponent();
      // ...other code.
   }
   
   private void button_Click(object sender, RoutedEventArgs e)
   {
      var scanner = new MediaScanner();
      MovieList = new ObservableCollection<MovieInfo>(scanner.ScanAll().OrderBy(x => x.Title));
   }
   
   // ...other code.
}

视图模型示例,以防您想移动到 MVVM。

public class MyViewModel : INotifyPropertyChanged
{
   private ObservableCollection<MovieInfo> _movieList;

   public ObservableCollection<MovieInfo> MovieList
   {
      get => _movieList;
      set
      {
         if (_movieList == value)
            return;

         _movieList = value;
         OnPropertyChanged();
      }
   }

   // ...other code.

   public event PropertyChangedEventHandler PropertyChanged;

   protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
   {
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
   }
}

最后一点,您应该考虑重用 ObservableCollection<MovieInfo> MovieList 而不是每次都创建和分配一个新的。这种类型的集合提供了添加、删除和替换项目的更改通知,这些通知将自动反映在用户界面中。暴露一个可观察的集合,而不是修改,替换它,是没有意义的。如果一个集合总是被替换,一个简单的 List<T> 会做同样的事情。