2013-02-14 64 views
5

मैं एक समर्थन उपकरण पर काम कर रहा हूं जो में एकाधिक TabItem एस प्रदर्शित करता है। प्रत्येक TabItem एक कर्मचारी का प्रतिनिधित्व करता है, और इनमें से प्रत्येक कर्मचारी Tab एस के भीतर एक और TabControl है जिसमें अतिरिक्त TabItem एस है। ये TabItem एस उस कर्मचारी के लिए आउटलुक फ़ोल्डर्स का प्रतिनिधित्व करते हैं (जैसे "वर्किंग", "पूर्ण", आदि)। इनमें से प्रत्येक फ़ोल्डर TabItem एस में ListBox है जो ObservableCollectionMailItem एस से संबंधित है जो उस Outlook फ़ोल्डर से संबंधित है। ये विशाल संग्रह नहीं हैं - ListBox प्रति केवल एक दर्जन या उससे अधिक आइटम। हालांकि, कुल मिलाकर, सभी TabItem एस में अनुमानतः 100 आइटम या तो हो सकता है।एकाधिक ListBoxes populating जब एक उत्तरदायी WPF UI बनाने की चाल क्या है?

जिस तरीके से मैंने वर्तमान में एप्लिकेशन बनाया है वह यह है कि ऐप उचित कर्मचारी टैब और उप-टैब के साथ स्क्रीन को ऊपर खींचता है और पॉप्युलेट करता है। यह प्रक्रिया काफी तेज़ है और मैं खुश हूं। मैंने एक स्टेटिक Global.System.Timer बनाया है कि सभी फ़ोल्डर TabItem का कोड-बैक सिंक्रनाइज़ किया गया है। तो हर 5 मिनट में एप्लिकेशन सभी ObserverableCollection एस साफ़ कर देगा और Outlook फ़ोल्डरों को फिर से स्कैन करेगा।

समस्या यह है कि स्कैन प्रक्रिया एप्लिकेशन को रोक देता है। मैं एक पृष्ठभूमि प्रक्रिया के रूप में आउटलुक से मेल इकट्ठा करने के लिए है, तो एक RunWorkerCompleted विधि है कि फिर एक this.Dispatcher.BeginInvoke प्रक्रिया है कि संबंधित ObservableCollection को साफ करता है तो List<MailItem> वापस ObservableCollection करने से आइटम कहते हैं चलाता है के लिए एक List<MailItem> वस्तु पारित एक BackgroundWorker उपयोग करने की कोशिश की है। मैंने यह Dispatcher को निम्न प्राथमिकता पर भी सेट किया है।

इसके बावजूद, एप्लिकेशन स्कैन/पॉप्युलेट ListBox प्रक्रिया के दौरान बहुत घबराहट महसूस कर रहा है। मैं इस बारे में अस्पष्ट हूं कि इसे बेहतर तरीके से कैसे डिजाइन किया जाए और मैं मानता हूं कि मैं इसके लिए कुछ नया हूं। मुझे एहसास है कि ObservableCollection एस में से प्रत्येक को साफ़ करना अक्षम है, लेकिन आउटलुक फ़ोल्डर परिवर्तन घटनाएं विशेष रूप से विश्वसनीय नहीं हैं, इसलिए मुझे सभी MailItem एस का बीमा करने के लिए हर बार एक ब्रूट फोर्स फिर से स्कैन करने की आवश्यकता होती है।

नीचे WPF नियंत्रण के लिए मेरा कोड है जिसमें ListBox शामिल है। ध्यान रखें कि इनमें से 10 में से ListBox नियंत्रण एक साथ सक्रिय हैं।

// 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); 
      } 
     } 
    } 
+0

, टैब किए गए दृष्टिकोण mailreader कि तक 5000+ आइटम के साथ फ़ोल्डर्स शामिल थोड़ा अजीब आप इस तरह के कम डेटा के साथ इस तरह बड़ा प्रदर्शन के मुद्दों कर रहे हैं, मैं एक ऐसी ही ऐप्लिकेशन है, लगता है और इस यूआई लटका नहीं करता है , किस प्रकार का 'टाइमर' ग्लोबलस्टैटिक्स टिमर 'है, मैं' थ्रेडिंग टिमर 'का उपयोग करता हूं जो' पृष्ठभूमिवर्कर 'की आवश्यकता को समाप्त करता है, क्या इन मेल आइटम्स से संबंधित छवियां भी हैं? –

+0

क्या RunWorker पूर्ण हैंडलर थ्रेड पर नहीं चला है जहां BackgroundWorker बनाया गया था? यदि ऐसा है तो आपको UI थ्रेड पर कोड चलाने के लिए डिस्पैचर का उपयोग करने की आवश्यकता नहीं है क्योंकि आप पहले ही यूआई थ्रेड पर हैं। – Andy

उत्तर

1

आपकी आवश्यकता के लिए विशेष रूप से WPF में, आपको दृश्य को उत्तरदायी रखने के लिए टाइमर या पृष्ठभूमि कार्यकर्ता का उपयोग नहीं करना चाहिए। इसके बजाय आपको अपने ऐप को एमवीवीएम पैटर्न के साथ डिजाइन करना चाहिए। एमवीवीएम मॉडल, व्यू और व्यू मॉडल है, जहां मॉडल में कोई बदलाव है, मॉडल मॉडल को अपडेट करता है, और व्यू मॉडल दृश्य को अपडेट करता है। यह सिर्फ "INotifyPropertyChanged" इंटरफ़ेस को विरासत में प्राप्त करके किया जाता है।

यहाँ एक सरल उदाहरण

Xaml हिस्सा है:

<Window x:Class="SimpleMVVM.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="259" Width="445"> 
    <Grid Margin="0,0,2,-3"> 
     <Button x:Name="button" Content="Button" HorizontalAlignment="Left" Margin="10,33,0,0" VerticalAlignment="Top" Width="75"/> 
     <Label x:Name="label" Content="{Binding Name}" HorizontalAlignment="Left" Margin="103,23,0,0" VerticalAlignment="Top" Width="220" BorderBrush="Black" BorderThickness="1" Height="32" Padding="0"/> 

    </Grid> 
</Window> 

और .cs भाग

using System.ComponentModel; 
using System.Windows; 

namespace SimpleMVVM 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     private AnimalViewModel _animal= new AnimalViewModel(); 

     public MainWindow() 
     { 
      InitializeComponent(); 

      DataContext = _animal; 
      button.Click += (sender, e) => _animal.Name = "Taylor" ; 
     } 
    } 

    public class AnimalViewModel : AnimalModel 
    { 
     public AnimalViewModel() 
     { 
     }   
    } 

    public class AnimalModel : INotifyPropertyChanged 
    { 
     private string _name; 

     public event PropertyChangedEventHandler PropertyChanged; 

     public string Name 
     { 
      get { return _name; } 
      set 
      { 
       if (_name != value) 
       { 
        _name = value; 
        OnPropertyChanged("Name"); 
       } 
      } 
     } 

     private void OnPropertyChanged(string propertyName) 
     { 
      if (PropertyChanged != null) 
      { 
       PropertyChangedEventArgs args = new PropertyChangedEventArgs(propertyName); 
       PropertyChanged(this, args); 
      } 
     } 
    } 

} 

कोई कल्पना करो कि बटन क्लिक अद्यतन अनुसूचक से शुरू हो रहा है, तो आप मॉडल पहले अपडेट करें जो दृश्य को ट्रिगर करने के लिए एक संपत्ति को बदल देता है।

इस पैटर्न का उपयोग करके आपका कोड अधिक विश्वसनीय होगा।

मुझे उम्मीद है कि इससे मदद मिलती है।

सादर Jegan

+0

एह। आपका व्यूमोडेल कहां है? मैं केवल दृश्य और मॉडल देखता हूं। –

+0

जैसा कि आपने बताया है कोड संपादित किया गया है! – Jegan

+0

आपका कोड ठीक है, लेकिन मुझे यकीन नहीं है कि आप इसे एमवीएमसी कह सकते हैं। मैंने कभी भी एम –