Связывание наблюдаемой коллекции с ListBox в XAML - PullRequest
9 голосов
/ 07 октября 2011

Я провел много часов с этой проблемой.

У меня есть класс с данными:

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 ]

28 голосов
/ 08 октября 2011

Следует отметить несколько моментов

  • Создать свойства public, а не private.
  • Создать переменные private.
  • Следовать соглашениям об именах ине добавляйте class за классом.
  • ItemsSource, который вы предоставляете, должен соответствовать области данных. В моем примере список пользователей в области класса и я предоставили событие ItemSource on Window Loaded.

Вот полный пример кода. В этом я вложил элемент Grid Control в 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 голосов
/ 07 октября 2011

Вам нужно сделать 2 вещи:

Во-первых, установить DataContext любого элемента (Window / UserControl / что угодно), содержащего ваш ListBox для объекта, который выглядит следующим образом:

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

Это модель вашего представления, с которой вы хотите связать.

Во-вторых, измените привязку на ItemsSource="{Binding Path=users}".Это переводит в "установить значение моего ItemsSource свойства равным значению свойства users для this.DataContext. Поскольку DataContext наследуется от родителя, и вы устанавливаете это для класса ViewModel выше,ваш ListBox теперь будет отображать ваш список пользователей.

...