Программно WPF listbox.ItemsSource обновление - PullRequest
2 голосов
/ 25 марта 2011

Я делаю такую ​​программу, как мессенджер, в которой все контакты находятся в списке с относительными состояниями контактов.Циклический Я получаю XML с контактами были обновлены с течением времени, а затем обновляет состояния в классе привязки под названием «Контакты».

Класс Контакты имеет фильтр для отображения только определенных контактов по их состоянию, "онлайн, в гостях, занят, .. "но не в автономном режиме, например ....

Какой-то код:

public class Contacts : ObservableCollection<ContactData>
{
    private ContactData.States _state = ContactData.States.Online | ContactData.States.Busy;
    public ContactData.States Filter { get { return _state; } set { _state = value; } }
    public IEnumerable<ContactData> FilteredItems
    {
        get { return Items.Where(o => o.State == _state || (_state & o.State) == o.State).ToArray(); }
    }
    public Contacts()
    {
        XDocument doc = XDocument.Load("http://localhost/contact/xml/contactlist.php");
        foreach (ContactData data in ContactData.ParseXML(doc)) Add(data);
    }
}

Часть обновления:

    void StatusUpdater(object sender, EventArgs e)
    {
        ContactData[] contacts = ((Contacts)contactList.Resources["Contacts"]).ToArray<ContactData>();
        XDocument doc = XDocument.Load("http://localhost/contact/xml/status.php");
        foreach (XElement node in doc.Descendants("update"))
        {
            var item = contacts.Where(i => i.UserID.ToString() == node.Element("uid").Value);
            ContactData[] its = item.ToArray();
            if (its.Length > 0) its[0].Data["state"] = node.Element("state").Value;
        }
        contactList.ListBox.ItemsSource = ((Contacts)contactList.Resources["Contacts"]).FilteredItems;
    }

Xaml Editor

Моя проблема в том, что когда ItemsSource переназначает значение списка, программа задерживается на несколько секунд, пока не завершит обновление интерфейса контактов (в настоящее время 250 имитируется).

Как я могуизбежать этой надоедливой проблемы?

Редактировать: я пытался с Thread и после с BackgroundWorker, но ничего не изменилось ... Когда я вызываю Dispatcher.Invoke происходит отставание.

Класс ContactData

public class ContactData : INotifyPropertyChanged
{
    public enum States { Offline = 1, Online = 2, Away = 4, Busy = 8 }
    public event PropertyChangedEventHandler PropertyChanged;
    public int UserID 
    {
        get { return int.Parse(Data["uid"]); }
        set { Data["uid"] = value.ToString(); NotifyPropertyChanged("UserID"); }
    }
    public States State 
    {
        get { return (States)Enum.Parse(typeof(States), Data["state"]); }
        //set { Data["state"] = value.ToString(); NotifyPropertyChanged("State"); }
        //correct way to update, i forgot to notify changes of "ColorState" and "BrushState"
        set 
        { 
            Data["state"] = value.ToString(); 
            NotifyPropertyChanged("State");
            NotifyPropertyChanged("ColorState");
            NotifyPropertyChanged("BrushState");
        }
    }
    public Dictionary<string, string> Data { get; set; }
    public void Set(string name, string value) 
    {
        if (Data.Keys.Contains(name)) Data[name] = value;
        else Data.Add(name, value);
        NotifyPropertyChanged("Data");
    }
    public Color ColorState { get { return UserStateToColorState(State); } }
    public Brush BrushState { get { return new SolidColorBrush(ColorState); } }
    public string FullName { get { return Data["name"] + ' ' + Data["surname"]; } }

    public ContactData() {}
    public override string ToString()
    {
        try { return FullName; }
        catch (Exception e) { Console.WriteLine(e.Message); return base.ToString(); }
    }
    Color UserStateToColorState(States state)
    {
        switch (state)
        {
            case States.Online: return Colors.LightGreen;
            case States.Away: return Colors.Orange;
            case States.Busy: return Colors.Red;
            case States.Offline: default: return Colors.Gray;
        }
    }

    public void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }  

    public static ContactData[] ParseXML(XDocument xmlDocument)
    {
        var result = from entry in xmlDocument.Descendants("contact")
        select new ContactData { Data = entry.Elements().ToDictionary(e => e.Name.ToString(), e => e.Value) };
        return result.ToArray<ContactData>();
    }
}

Ответы [ 3 ]

2 голосов
/ 25 марта 2011

Я разработал аналогичное программное обеспечение: огромный список контактов с данными (присутствием и прочим), которые обновляются довольно часто.Решение, которое я использовал, отличается: вместо того, чтобы каждый раз обновлять весь источник данных, что довольно дорого, реализуйте класс ViewModel для каждого контакта.Класс ViewModel должен реализовывать INotifiyPropertyChanged.В этот момент, когда вы анализируете XML, вы обновляете свойства ContactViewModel, и это вызывает корректные события NotifyPropertyChanged, которые обновляют правильный фрагмент пользовательского интерфейса.Это может быть дорого, если вы одновременно обновляете множество свойств для большого количества контактов, для этого вы можете реализовать какое-то кэширование, например: contactViewModel.BeginUpdate () contactViewModel.Presence = Presence.Available;..... другие обновления contactViewModel.EndUpdate ();// в этой точке запускаем события PropertyCHanged.

Другой момент: держите отдельную коллекцию ObservableCollection привязанной к ListBox и никогда не изменяйте свойство itemssource: вы рискуете потерять текущий выбор, положение прокрутки и т. д. динамически добавлять / удалять элементы изколлекция привязана к списку.

Buon divertimento e in bocca al lupo: -)

1 голос
/ 25 марта 2011

Переместить загрузку и анализ информации о статусе контакта в другой поток.

0 голосов
/ 25 марта 2011

Строка, где вы назначаете ItemsSource, я бы вставил в другой поток, но помните о вызове, иначе у вас будут раздражающие ошибки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...