Привязка наблюдаемой коллекции к ListBox в XAML
Я провел много часов с этой проблемой.
у меня есть класс с данными:
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<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. Я пробовал несколько способов, но у меня не получается.
последний, который я пробовал, дал мне ошибку записи:
ресурс "пользователи" не может быть разрешен.
<ListBox Grid.Column="0" Name="userViewLeft" ItemsSource="{Binding Source={StaticResource users} }" />
2 ответов
некоторые моменты следует отметить
- Сделать Свойства
public
, а неprivate
. - Сделать Переменные
private
. - следуйте соглашениям об именах и не добавляйте
class
позади класса. -
ItemsSource
вы предоставляете должны быть в соответствии с областью данных, в моем примере userlist в области класса, и я предоставил ItemSource on Window Loaded event.
вот полный пример кода, в этом у меня нет вложенный элемент управления Grid внутри 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 позади:
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();
}
}
}
вам нужно сделать 2 вещи:
во-первых, установить DataContext
любой элемент (Window
/UserControl
/ whatever) содержит ваш ListBox
объекту, который выглядит так:
public class ViewModel
{
public ViewModel() { this.users = new userListClass(); }
public userListClass users { get; private set; }
}
это ваша модель представления, и это то, к чему вы хотите привязаться.
во-вторых, измените привязку на ItemsSource="{Binding Path=users}"
. Это переводится в "установить значение my ItemsSource
свойство к значению свойства users
on this.DataContext
. Потому что DataContext
наследуется от родителя, и вы установили это на ViewModel
классом выше, ваш ListBox
теперь отобразится список пользователей.