I am working on a support tool that displays multiple TabItem
s in a TabControl
. Each TabItem
represents an employee, and within each of these employee Tab
s there is another TabControl
which contains additional TabItem
s. These TabItem
s represent Outlook folders for that employee (like "Working", "Completed", etc). Each of these folder TabItem
s contains a ListBox
that is bound to an ObservableCollection
of MailItem
s that pertain to that Outlook folder. These aren't huge collections - only a dozen or so items per ListBox
. Although, in total, across all TabItem
s there could conceivably be 100 items or so.
The way I have currently built the application is that the app fires up and populates the screen with the appropriate employee tabs and sub-tabs. This process is fairly quick and I'm happy. I have created a Static Global.System.Timer
that all folder TabItem
's code-behind is synchronized with. So every 5 minutes the application will clear all ObserverableCollection
s and re-scan the Outlook folders.
The problem is that the scan process brings the application to a halt. I have tried using a BackgroundWorker
to gather mail from Outlook as a background process, then pass a List<MailItem>
object to a RunWorkerCompleted
method that then runs a this.Dispatcher.BeginInvoke
process that clears the respective ObservableCollection
then adds the items from the List<MailItem>
back to the ObservableCollection
. I've even set this Dispatcher
to the lower priority.
Despite this, the application is very clunky feeling during the scan/populate ListBox
process. I am unclear on how to better design this and I admit I am somewhat new to this. I realize that clearing out each of the ObservableCollection
s is inefficient, but Outlook folder change events aren't particularly reliable, so I need to do a brute force re-scan every once in a while to insure all MailItem
s are represented.
Below is my code for the WPF control that contains the ListBox
. Keep in mind that there are about 10 of these ListBox
controls active at once.
// 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);
}
}
}