将可观察集合绑定到XAML中的ListBox

我花了很多时间来解决这个问题。

我有一个数据类:

public class User : INotifyPropertyChanged { private int _key; private string _fullName; private string _nick; public int Key { get{return _key;} set { _key = value; NotifyPropertyChanged("Key"); } } public string Nick { get { return _nick; } set { _nick = value; NotifyPropertyChanged("Nick"); } } public string FullName { get { return _fullName; } set { _fullName = value; NotifyPropertyChanged("FullName"); } } public User() { Nick = "nickname"; FullName = "fullname"; } public User(String nick, String name, int key) { Nick = nick; FullName = name; } //INotifyPropertyChanged implementation public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged(String propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } public override string ToString() { return string.Format("{0} {1}, {2}", Key, Nick, FullName); } } 

接下来我有一个带有observablecollection userClass类的类:

 public class UserList : ObservableCollection { public UserList (){} ~UserList () { //Serialize(); } public void Serialize(ObservableCollection usersColl) { FileStream fs = new FileStream("DataFile.dat", FileMode.Create); BinaryFormatter formatter = new BinaryFormatter(); try { formatter.Serialize(fs, usersColl); } catch (SerializationException e) { Console.WriteLine("Failed to serialize. Reason: " + e.Message); throw; } finally { fs.Close(); } } public void Deserialize() { FileStream fs = new FileStream("DataFile.dat", FileMode.Open); try { BinaryFormatter formatter = new BinaryFormatter(); //users = (Hashtable) formatter.Deserialize(fs); //usersColl = (ObservableCollection)formatter.Deserialize(fs); } catch (SerializationException e) { MessageBox.Show(" Error: " + e.Message); throw; } finally { fs.Close(); } } } 

实际上,经过大量的编辑测试后,大部分代码都无法正常工作,比如序列化。 但是数据绑定和绑定不是我现在要解决的问题。

所以我有这个集合,并希望将它绑定到listBox。 我尝试了几种方法,但没有让它起作用。

我试过的最后一个给了我写错误:

无法解析资源“用户”。

  

有些要点需要注意

  • 将属性设为public而非private
  • 将变量设为private
  • 遵循命名约定,不要在class后面添加课程。
  • 你提供的ItemsSource应该按照数据的范围,在我的例子中,类范围内的用户列表和我在Window Loaded事件上提供了ItemSource。

这是一个完整的示例代码,在此我已经嵌套了ListBox中的Grid Control,因为稍后您可以更改VirtualizingStackPanel的ListBox属性。 因此,当您在列表上进行大量更新时,它会带来巨大的性能提升。 你也可以使用BindingList ,这在我看来比ObservableCollection性能更好。

用户类:

  public class User : INotifyPropertyChanged { private int _key; private string _fullName; private string _nick; public int Key { get { return _key; } set { _key = value; NotifyPropertyChanged("Key"); } } public string NickName { get { return _nick; } set { _nick = value; NotifyPropertyChanged("NickName"); } } public string Name { get { return _fullName; } set { _fullName = value; NotifyPropertyChanged("Name"); } } public User(String nick, String name, int key) { this.NickName = nick; this.Name = name; this.Key = key; } public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged(String propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } public override string ToString() { return string.Format("{0} {1}, {2}", Key, NickName, Name); } } 

用户列表类:

  public class Users : ObservableCollection { public Users() { Add(new User("Jamy", "James Smith", Count)); Add(new User("Mairy", "Mary Hayes", Count)); Add(new User("Dairy", "Dary Wills", Count)); } } 

XAML:

                     

XAML代码背后:

 public partial class MainWindow : Window { public static Users userslist = new Users(); DispatcherTimer timer = new DispatcherTimer(); public MainWindow() { InitializeComponent(); this.Loaded += new RoutedEventHandler(MainWindow_Loaded); } void MainWindow_Loaded(object sender, RoutedEventArgs e) { timer.Interval = DateTime.Now.AddSeconds(10) - DateTime.Now; timer.Tick += new EventHandler(timer_Tick); UserList.ItemsSource = userslist; } void timer_Tick(object sender, EventArgs e) { userslist.Add(new User("Jamy - " + userslist.Count, "James Smith", userslist.Count)); userslist.Add(new User("Mairy - " + userslist.Count, "Mary Hayes", userslist.Count)); userslist.Add(new User("Dairy - " + userslist.Count, "Dary Wills", userslist.Count)); } private void button1_Click(object sender, RoutedEventArgs e) { if (button1.Content.ToString() == "Start") { button1.Content = "Stop"; timer.Start(); } else { button1.Content = "Start"; timer.Stop(); } } } 

你需要做两件事:

首先,将包含ListBox的任何元素( Window / UserControl / whatever)的DataContext设置为如下所示的对象:

 public class ViewModel { public ViewModel() { this.users = new userListClass(); } public userListClass users { get; private set; } } 

这是您的视图模型,它是您要绑定的内容。

其次,将您的绑定更改为ItemsSource="{Binding Path=users}" 。 这转换为“将我的ItemsSource属性的值设置为this.DataContext上的属性users的值。因为DataContext是从父级inheritance的,并且您将其设置为上面的ViewModel类,所以ListBox现在将显示您的用户列表。