我正在做一个像Messenger这样的程序,它在列表框中包含所有联系人以及联系人的相对状态。 循环我得到一个 xml,其中联系人随着时间的推移而更新,然后更新名为“联系人”的绑定(bind)类中的状态。
联系人类有一个过滤器,可以按状态仅显示某些联系人,“在线、离开、忙碌……”,但不显示离线状态,例如......
一些代码:
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;
}
我的问题是,当 ItemsSource 重新分配列表框的值时,程序会延迟几秒钟,直到完成更新联系人 UI(当前模拟 250 个)。
如何避免这个恼人的问题?
编辑: 我尝试使用Thread,然后尝试使用BackgroundWorker,但没有任何改变...... 当我调用 Dispatcher.Invoke 时,会发生延迟。
联系数据类
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>();
}
}
最佳答案
我开发了一个类似的软件:一个巨大的联系人列表,其中的数据(状态和其他内容)更新得非常频繁。 我使用的解决方案有所不同:不是每次都更新整个项目源(这相当昂贵),而是为每个联系人实现一个 ViewModel 类。 ViewModel 类应该实现 INotifiyPropertyChanged。 此时,当您解析 XML 时,您会更新 ContactViewModel 属性,这将触发正确的 NotifyPropertyChanged 事件,从而更新正确的 UI 部分。 如果您同时更新大量联系人的大量属性,这可能会很昂贵,因为您可以实现某种缓存,例如: contactViewModel.BeginUpdate() contactViewModel.Presence = Presence.Available; .....其他更新 contactViewModel.EndUpdate();//此时触发PropertyCHanged事件。
还有一点: 将单独的 ObservableCollection 绑定(bind)到 ListBox 并且永远不要更改 itemssource 属性:您可能会丢失当前选择、滚动位置等。 从绑定(bind)到列表框的集合中动态添加/删除元素。
Buon divertimento e in bocca al lupo :-)
关于c# - 以编程方式 WPF listbox.ItemsSource 更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5431761/