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>
会做同样的事情。
我在设置自动绑定时遇到问题。
我有一个简单的 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>
会做同样的事情。