在XAML中将可观察对象集合绑定到ListBox
本文关键字:集合 绑定 ListBox 对象 观察 XAML | 更新日期: 2023-09-27 18:10:45
我花了很多时间来解决这个问题。
我有一个类的数据:
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);
}
}
接下来我有一个类userClass的observablecollection:
public class UserList : ObservableCollection<UserList>
{
public UserList (){}
~UserList ()
{
//Serialize();
}
public void Serialize(ObservableCollection<UserList> 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<userClass>)formatter.Deserialize(fs);
}
catch (SerializationException e)
{
MessageBox.Show(" Error: " + e.Message);
throw;
}
finally
{
fs.Close();
}
}
}
事实上,经过大量的测试和编辑后,大部分代码无法工作,比如序列化。但是数据绑定是不必要的,绑定是我现在正在解决的问题。
所以我有这个集合,并希望将其绑定到listBox。我试了好几种方法,但都没用。
我最后一次尝试给我写错误:
资源'users'无法解析。
<ListBox Grid.Column="0" Name="userViewLeft" ItemsSource="{Binding Source={StaticResource users} }" />
注意事项
- 设置属性为
public
而不是private
。 - Make Variables .
private
. - 遵循命名规范,不要在类后面添加
class
。 -
ItemsSource
你提供的应该是根据数据的范围,在我的例子中,类范围内的用户列表和我已经提供了ItemSource on Window Loaded事件。
这是一个完整的示例代码,在这里我已经嵌套了网格控件在ListBox,因为以后你可以改变ListBox属性VirtualizingStackPanel。因此,当列表上有大量更新时,它将提供巨大的性能提升。你也可以使用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<User>
{
public Users()
{
Add(new User("Jamy", "James Smith", Count));
Add(new User("Mairy", "Mary Hayes", Count));
Add(new User("Dairy", "Dary Wills", Count));
}
}
XAML:
<Grid>
<Button Content="Start" Height="23" HorizontalAlignment="Left" Margin="416,12,0,0" x:Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
<ListBox x:Name="UserList" HorizontalContentAlignment="Stretch" Margin="12,41,12,12">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition Width="150" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Key}" Margin="3" Grid.Column="0" />
<TextBlock Text="{Binding NickName}" Margin="3" Grid.Column="1" />
<TextBlock Text="{Binding Name}" Margin="3" Grid.Column="2" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
XAML Code behind:
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
继承自父类,并且您将其设置为上面的ViewModel
类,所以您的ListBox
现在将显示您的用户列表。