我正在开发一个支持工具,该工具在TabControl
中显示多个TabItem
。每个TabItem
代表一名雇员,并且在这些雇员Tab
中的每一个中都有另一个TabControl
,其中包含额外的TabItem
。这些TabItem
代表该员工的Outlook文件夹(如“正在工作”,“已完成”等)。这些文件夹中的每一个都包含ListBox
,该ListBox
绑定到与该Outlook文件夹相关的ObservableCollection
的MailItem
。这些并不是庞大的收藏品 - 每ListBox
只有十几件。尽管在所有的TabItem
中总共可以有100个项目左右。在填充多个ListBox时创建响应式WPF UI的诀窍是什么?
我目前构建应用程序的方式是,应用程序启动并使用适当的员工选项卡和子选项卡填充屏幕。这个过程相当快,我很高兴。我创建了一个静态Global.System.Timer
,即所有文件夹TabItem
的代码隐藏都与之同步。因此,每5分钟应用程序将清除所有ObserverableCollection
s并重新扫描Outlook文件夹。
问题是扫描过程会导致应用程序停止。我已经使用BackgroundWorker
从Outlook邮件收集作为后台进程,然后通过一个List<MailItem>
对象到RunWorkerCompleted
方法然后运行this.Dispatcher.BeginInvoke
过程,清除各自ObservableCollection
然后加上从List<MailItem>
回ObservableCollection
的项目尝试。我甚至将Dispatcher
设置为较低的优先级。
尽管如此,在扫描/填充ListBox
过程中,应用程序仍然非常笨重。我不清楚如何更好地设计这一点,我承认我对此有点新鲜。我意识到清除ObservableCollection
中的每一个都是低效的,但Outlook文件夹更改事件不是特别可靠,所以我需要每隔一段时间进行一次蛮力重新扫描,以确保所有MailItem
都被表示。
下面是我的WPF控件的代码,其中包含ListBox
。请记住,这些ListBox
控件中大约有10个同时处于活动状态。
// This entire UserControl is essentially a ListBox control
public partial class TicketListView : UserControl
{
private TicketList _ticketList; //this is the ObservableCollection object
private Folder _folder; // Outlook Folder
public TicketListView(Folder folder)
{
InitializeComponent();
_ticketList = this.FindResource("TicketList") as TicketList;
_folder = folder;
GlobalStatics.Timer.Elapsed += new System.Timers.ElapsedEventHandler(Timer_Elapsed);
}
private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
Refresh();
}
private void Refresh()
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.RunWorkerAsync();
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
List<MailItem> tickets = new List<MailItem>();
string filter = TicketMonitorStatics.TicketFilter(14);
Items items = _folder.Items.Restrict(filter);
try
{
foreach (MailItem mi in items.OfType<MailItem>())
{
tickets.Add(mi);
}
}
catch (System.Exception) { }
e.Result = tickets;
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
List<MailItem> tickets = e.Result as List<MailItem>;
this.Dispatcher.BeginInvoke(new System.Action(delegate
{
_ticketList.Clear();
PopulateList(tickets);
}));
BackgroundWorker worker = sender as BackgroundWorker;
worker.Dispose();
}
private void PopulateList(List<MailItem> ticketList)
{
foreach (MailItem mi in ticketList)
{
this.Dispatcher.BeginInvoke(new System.Action(delegate
{
_ticketList.Add(mi);
}), System.Windows.Threading.DispatcherPriority.SystemIdle);
}
}
}
似乎有点奇怪您有这样的小数据这么大的性能问题,我有一个类似的应用程序,选项卡式前景邮件阅读器,其中包括与高达5000多个项目的文件夹,这不挂UI什么样的'Timer'是'GlobalStatics.Timer',我使用'Threading.Timer'来消除'BackgroundWorker'的需要,是否还有与这些邮件项目相关的图像? – 2013-02-14 03:25:32
RunWorkerCompleted处理程序是否在创建BackgroundWorker的线程上运行?如果是这种情况,您应该不需要使用分派器在UI线程上运行代码,因为您已经在UI线程中。 – Andy 2013-03-13 12:44:25