Сортировка ListBox после обновления элементов, привязывает ли Items.SortDescription INotifyPropertyChanged? - PullRequest
1 голос
/ 01 апреля 2011

Обновление большого вопроса перед продолжением: События Items.SortDescription запускаются событиями INotifyPropertyChanged?

Из кода другого вопроса: Программно WPF listbox.ItemsSource update , я решил использовать Items.Refres (), которые замедляют выполнение ...

Но после того, как я начинаю сортировать элементы, проблема повторяется.

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

Я получаю потерянные данные, такие как проблемы с мышью и клавиатурой, если циклически вызываю функцию для Clear () и повторно добавляю SortDescription.

Некоторый код:

Потоковый таймер:

    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("UserID").Value);
            ContactData[] its = item.ToArray();
            if (its.Length > 0)
            {
                its[0].UpdateFromXML(node);
            }
        }
        Dispatcher.Invoke(DispatcherPriority.Normal, new Action( () => { contactList.SortAndGroup(); } ));
    }

SortAndGroup () // Это создает мою проблему:

    public void SortAndGroup()
    {
        MyListBox.Items.SortDescriptions.Clear();
        MyListBox.Items.SortDescriptions.Add(new SortDescription("State", ListSortDirection.Ascending));
    }

ItemsSource:

public class Contacts : ObservableCollection<ContactData>, INotifyPropertyChanged
{
    private ContactData.States _state = ContactData.States.Online | ContactData.States.Busy;
    public new event PropertyChangedEventHandler PropertyChanged;
    public ContactData.States Filter 
    { 
        get { return _state; } 
        set 
        { 
            _state = value;
            NotifyPropertyChanged("Filter");
            NotifyPropertyChanged("FilteredItems");
        } 
    }
    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);
    }
    public void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    } 
}

Класс исходных данных:

public class ContactData : INotifyPropertyChanged
{
    public enum States { Online = 1, Away = 2, Busy = 4, Offline = 128 }
    public event PropertyChangedEventHandler PropertyChanged;
    public int UserID 
    {
        get { return int.Parse(Data["UserID"]); }
        set { Data["UserID"] = value.ToString(); NotifyPropertyChanged("UserID"); }
    }
    public States State 
    {
        get { return (Data.Keys.Contains("State")) ? (States)Enum.Parse(typeof(States), Data["State"]) : States.Offline; }
        set 
        { 
            Data["State"] = value.ToString();
            NotifyStateChanged();
        }
    }
    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 System.Windows.Media.Imaging.BitmapImage Avatar
    {
        get 
        {
            return Utilities.Stream.Base64ToBitmapImage(Data["Avatar"]); 
        }
        set 
        { 
            Data["Avatar"] = Utilities.Stream.BitmapImageToBase64( value ); 
            NotifyPropertyChanged("Avatar"); 
        }
    }

    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 UpdateFromXML(XElement xEntry)
    {
        var result = xEntry.Elements().ToDictionary(e => e.Name.ToString(), e => e.Value);
        foreach (string key in result.Keys) if (key != "UserID")
        {
            if (Data.Keys.Contains(key)) Data[key] = result[key];
            else Data.Add(key, result[key]);
            char[] property = key.ToCharArray();
            property[0] = char.ToUpper(property[0]);
            NotifyPropertyChanged(new string(property));
        }
    }

    public void NotifyStateChanged()
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs("State"));
            PropertyChanged(this, new PropertyChangedEventArgs("ColorState"));
            PropertyChanged(this, new PropertyChangedEventArgs("BrushState"));
        }
    }

    public void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            if (this.GetType().GetProperty(propertyName) != null)
            {
                if (propertyName != "State")
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                else NotifyStateChanged();
            }
        }
    }

    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>();
    }
}

enter image description here

Ответы [ 3 ]

1 голос
/ 01 апреля 2011

Не совсем уверен, в чем ваша проблема, но вам может потребоваться добавить это, прежде чем добавить описание GroupDescription.

MyListBox.Items.GroupDescriptions.Clear();

Теперь вы добавили циклический комментарий, который имеет больше смысла.Почему бы вам не связать PagedCollectionView, а не отправить сортировку в элемент управления?

       PagedCollectionView itemListView = new PagedCollectionView(contacts);

        // Set the DataPager and ListBox to the same data source.
       itemListView.SortDescriptions.Clear();
       itemListView.SortDescriptions.Add(new SortDescription("State", ListSortDirection.Ascending));
       MyListBox.ItemsSource=itemListView;
0 голосов
/ 11 апреля 2011

Я оставлю это на будущее, если это кому-нибудь понадобится ... Теперь он работает плавно.

Я наконец исправил это так:

        View = (ListCollectionView)CollectionViewSource.GetDefaultView(ContactData.ParseXML(doc));
        View.SortDescriptions.Add(new SortDescription("State", ListSortDirection.Ascending));
        View.SortDescriptions.Add(new SortDescription("FullName", ListSortDirection.Ascending));
        MyListBox.ItemsSource = View.SourceCollection;

А в теме обновления:

        while (IsStatusUpdateRunnig)
        {
            ContactData[] contacts = ((ContactData[])View.SourceCollection);//MyListBox.ItemsSource);
            XDocument doc = XDocument.Load("http://localhost/contact/xml/status.php");
            foreach (XElement node in doc.Descendants("update"))
            {
                ContactData[] its = contacts.Where(i => i.UserID.ToString() == node.Element("UserID").Value).ToArray();
                if (its.Length > 0)
                {
                    its[0].UpdateFromXML(node);
                    Dispatcher.Invoke(new Action(() => { View.EditItem(its[0]); }));
                }
            }
            Dispatcher.Invoke(new Action(() => { View.CommitEdit(); }));
            System.Threading.Thread.Sleep(2000);
        }
0 голосов
/ 01 апреля 2011

AFAIK, используя GroupDescription, как вы делаете, это самый быстрый способ с ListBox, если вы не хотите реализовать элемент управления самостоятельно У вас сейчас проблемы с производительностью? Это должно работать достаточно быстро.

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