Sto lavorando a uno strumento di supporto che visualizza più TabItem
s in un TabControl
. Ogni TabItem
rappresenta un dipendente e all'interno di ciascuno di questi dipendenti Tab
s vi è un altro TabControl
che contiene ulteriori TabItem
s. Questi numeri TabItem
rappresentano cartelle di Outlook per quel dipendente (come "Lavoro", "Completato", ecc.). Ciascuna di queste cartelle TabItem
s contiene un numero ListBox
associato a uno ObservableCollection
di MailItem
s relativo a tale cartella di Outlook. Queste non sono raccolte enormi - solo una dozzina di articoli per ListBox
. Sebbene, in totale, tra tutti gli TabItem
s possano essere presumibilmente 100 articoli circa.Qual è il trucco per creare un'interfaccia utente WPF reattiva quando si popolano più ListBox?
Il modo in cui attualmente ho creato l'applicazione è che l'applicazione si attiva e popola lo schermo con le schede e sottoschede dipendenti appropriate. Questo processo è abbastanza veloce e sono felice. Ho creato uno statico Global.System.Timer
con cui il code-behind di tutte le cartelle è sincronizzato con. Quindi ogni 5 minuti l'applicazione cancellerà tutti i ObserverableCollection
e riscriverà le cartelle di Outlook.
Il problema è che il processo di scansione interrompe l'applicazione. Ho provato con un BackgroundWorker
per raccogliere la posta da Outlook come un processo in background, quindi passare un oggetto List<MailItem>
a un metodo RunWorkerCompleted
che poi esegue un processo this.Dispatcher.BeginInvoke
che cancella il rispettivo ObservableCollection
poi aggiunge gli oggetti dal List<MailItem>
indietro al ObservableCollection
. Ho persino impostato questo Dispatcher
sulla priorità più bassa.
Nonostante ciò, l'applicazione è molto fastidiosa durante il processo scan/populate ListBox
. Non sono chiaro su come progettare meglio questo e ammetto di essere un po 'nuovo in questo. Mi rendo conto che eliminare tutti gli ObservableCollection
s è inefficiente, ma gli eventi di modifica delle cartelle di Outlook non sono particolarmente affidabili, quindi è necessario eseguire una nuova scansione brute force ogni tanto per assicurare che tutti gli MailItem
s siano rappresentati.
Di seguito è riportato il mio codice per il controllo WPF che contiene ListBox
. Tieni presente che vi sono circa 10 di questi controlli ListBox
attivi contemporaneamente.
// 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);
}
}
}
Sembra un po 'strano che si stanno avendo questi problemi grandi prestazioni con tali dati poco, ho un'applicazione simile, mailreader prospettive a schede che include le cartelle con gli elementi FINO 5000+ e questo non si blocca l'interfaccia utente , Che tipo di 'Timer' è' GlobalStatics.Timer', io uso un 'Threading.Timer' che elimina la necessità di un' BackgroundWorker', ci sono anche le immagini associate a questi elementi di posta? –
Il gestore RunWorkerCompleted non viene eseguito sul thread in cui è stato creato BackgroundWorker? In questo caso non è necessario utilizzare un Dispatcher per eseguire il codice sul thread dell'interfaccia utente poiché si è già sul thread dell'interfaccia utente. – Andy