2009-12-30 16 views
25

मेरा प्रोटोटाइप "दस्तावेज़" प्रदर्शित करता है जिसमें "पृष्ठ" होते हैं जो थंबनेल छवियों द्वारा दर्शाए जाते हैं। प्रत्येक दस्तावेज़ में पृष्ठों की संख्या हो सकती है। उदाहरण के लिए, प्रत्येक 5 पृष्ठों वाले 1000 दस्तावेज़, या 1000 पृष्ठों के साथ 5 दस्तावेज़ प्रत्येक, या कहीं भी बीच में हो सकता है। दस्तावेज़ों में अन्य दस्तावेज नहीं हैं। मेरे xaml मार्कअप में मेरे पास ListBox है, जिसका ItemsTemplate एक आंतरिक इटम्स टेम्पलेट का संदर्भ देता है जिसमें ListBox भी है। मैं चयनित वस्तुओं के 2 स्तर चाहता हूं ताकि मैं दस्तावेजों या पृष्ठों पर विभिन्न परिचालन निष्पादित कर सकूं (हटाएं, विलय करें, नए स्थान पर जाएं, आदि)। आंतरिक इटम्स टेम्पलेट ListBox का उपयोग ItemsPanelTemplate के रूप में करता है।एक सूची बॉक्स के साथ WPF ListBox - UI वर्चुअलाइजेशन और स्क्रॉलिंग

परिदृश्य में जहाँ मैं कुछ पृष्ठों प्रत्येक (जैसे कि, 5 पृष्ठों वाले 10000 दस्तावेज) के साथ दस्तावेजों की एक बड़ी संख्या है के लिए, स्क्रॉल VirtualizingStackPanel द्वारा यूआई वर्चुअलाइजेशन के लिए बहुत धन्यवाद काम करता है। हालांकि, अगर मेरे पास बड़ी संख्या में पृष्ठ हैं तो मुझे समस्याएं हैं। 1000 पृष्ठों के साथ एक दस्तावेज़ केवल एक समय में लगभग 50 प्रदर्शित करेगा (जो भी स्क्रीन पर फिट बैठता है), और जब मैं स्क्रॉल करता हूं, बाहरी ListBox अगले दस्तावेज़ पर जाता है, 950 पृष्ठों को छोड़कर या जो दिखाई नहीं दे रहा था। इसके साथ, VirtualzingWrapPanel नहीं है इसलिए ऐप मेमोरी वास्तव में बढ़ जाती है।

मुझे आश्चर्य है कि मैं इस बारे में सही तरीके से जा रहा हूं, खासकर क्योंकि यह समझाने में मुश्किल है! मैं यूआई वर्चुअलाइजेशन का उपयोग करके 10000 दस्तावेज़ों को प्रदर्शित करने में सक्षम होना चाहता हूं (केवल स्क्रीन पर जो कुछ भी फिट बैठता है), UI वर्चुअलाइजेशन का उपयोग करके, और चिकनी स्क्रॉलिंग भी।

मैं यह सुनिश्चित कैसे कर सकता हूं कि अगले दस्तावेज़ को प्रदर्शित करने से पहले दस्तावेज़ में स्क्रॉलिंग सभी पृष्ठों के माध्यम से चलता है, और फिर भी UI वर्चुअलाइजेशन रखें? स्क्रॉलबार केवल अगले दस्तावेज़ पर जाने लगता है। एक ListBox के भीतर एक ListBox का उपयोग करने का मेरे वर्तमान विधि के साथ -

यह "दस्तावेज़" और "पृष्ठ" का प्रतिनिधित्व करने के तार्किक प्रतीत होता है?

मैं आपके विचारों की बहुत सराहना करता हूं। धन्यवाद।

उत्तर

24

जवाब यहाँ आश्चर्य की बात है:

  • आप ItemsControl का उपयोग करें या ListBox यदि आप व्यवहार आप अनुभव कर रहे हो जाएगा, जहां कंट्रोल स्क्रॉल "आइटम द्वारा" ताकि आप एक बार पूरे दस्तावेज़ पर कूद सकें, लेकिन
  • यदि आप इसके बजाय TreeView का उपयोग करते हैं, तो नियंत्रण आसानी से स्क्रॉल करेगा ताकि आप अपने दस्तावेज़ को और अगले में स्क्रॉल कर सकें, लेकिन यह अभी भी होगा वर्चुअलाइज करने में सक्षम

मुझे लगता है कि कारण WPF टीम इस व्यवहार चुना है कि TreeView आमतौर पर, आइटम है कि दृश्य क्षेत्र से बड़े होते हैं, जबकि आम तौर पर है ListBox तों नहीं है।

किसी भी मामले में, यह WPF में एक TreeView देखो बनाने के लिए और बस ItemContainerStyle संशोधित करके एक ListBox या ItemsControl की तरह काम करने के लिए तुच्छ है। यह बहुत सरल है। आप सिस्टम थीम फ़ाइल से अपने स्वयं के रोल या उचित टेम्पलेट पर प्रतिलिपि बना सकते हैं।

तो तुम कुछ इस तरह होगा:

<TreeView ItemsSource="{Binding documents}"> 
    <TreeView.ItemsPanel> 
    <ItemsPanelTemplate> 
     <VirtualizingStackPanel /> 
    </ItemsPanelTemplate> 
    </TreeView.ItemsPanel> 
    <TreeView.ItemContainerStyle> 
    <Style TargetType="{x:Type TreeViewItem}"> 
     <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="{x:Type TreeViewItem}"> 
      <ContentPresenter /> <!-- put your desired container style here with a ContentPresenter inside --> 
      </ControlTemplate> 
     </Setter.Value> 
     </Setter> 
    </Style> 
    </TreeView.ItemContainerStyle> 
    <TreeView.ItemTemplate> 
    <DataTemplate TargetType="{x:Type my:Document}"> 
     <Border BorderThickness="2"> <!-- your document frame will be more complicated than this --> 
     <ItemsControl ItemsSource="{Binding pages}"> 
      ... 
     </ItemsControl> 
     </Border> 
    </DataTemplate> 
    </TreeView.ItemTemplate> 
</TreeView> 

पिक्सेल आधारित स्क्रॉल और ListBox शैली एकाधिक चयन करें काम करने के लिए हो रही है एक साथ

आप इस तकनीक का उपयोग करते हैं पिक्सेल आधारित स्क्रॉल प्राप्त करने के लिए, आपके बाहरी आइटम नियंत्रण जो दस्तावेज़ दिखाते हैं वे एक सूची बॉक्स नहीं हो सकते हैं (क्योंकि ListBox TreeView या TreeViewItem का उप-वर्ग नहीं है)। इस प्रकार आप सभी सूची बॉक्स के बहुविकल्पीय समर्थन खो देते हैं। जहां तक ​​मैं कह सकता हूं, इन सुविधाओं को एक सुविधा या दूसरे के लिए अपना स्वयं का कोड शामिल किए बिना इन दोनों सुविधाओं का एक साथ उपयोग करने का कोई तरीका नहीं है।

आप एक ही नियंत्रण में कार्यक्षमता के दोनों सेट की जरूरत है, तो आप मूल रूप से कई विकल्प हैं:

  1. लागू TreeViewItem का एक उपवर्ग में बहु चयन अपने आप को। बाहरी नियंत्रण के लिए TreeView के बजाय TreeViewItem का उपयोग करें, क्योंकि यह कई बच्चों को चुनने की अनुमति देता है। ItemContainerStyle के अंदर टेम्पलेट में: ContentPresenter के चारों ओर एक चेकबॉक्स जोड़ें, टेम्पलेट चेकबॉक्स को IsSelected से बांधें, और इच्छित रूप से प्राप्त करने के लिए चेकबॉक्स को नियंत्रण टेम्पलेट के साथ स्टाइल करें। फिर मल्टीइलेक्स्ट के लिए Ctrl-Click और Shift-Click को संभालने के लिए अपने माउस ईवेंट हैंडलर जोड़ें।

  2. वर्चुअलाइजिंग पैनेल के उप-वर्ग में पिक्सेल-स्क्रॉल वर्चुअलाइजेशन को कार्यान्वित करें। यह अपेक्षाकृत सरल है, क्योंकि अधिकांश वर्चुअलाइजिंगस्टैक पैनेल की जटिलता गैर-पिक्सेल स्क्रॉलिंग और कंटेनर रीसाइक्लिंग से संबंधित है। Dan Crevier's Blog वर्चुअलाइजिंग पैनेल को समझने के लिए कुछ उपयोगी उल्लंघन है।

+0

यह दृष्टिकोण वास्तव में यूआई वर्चुअलाइजेशन तक मेरे लिए काम करता है। अब मुझे सूची बॉक्स (इस मामले में पेज या दस्तावेज़) चुनने के लिए सूची जैसे सूची बॉक्स प्राप्त करने की आवश्यकता है। मैं ListBox के समान एकाधिक और विस्तारित चयन मोड कैसे प्राप्त कर सकता हूं? –

+0

इसके अलावा, मैं आइटम्स कंट्रोल के भीतर आइटमपैनल टेम्पलेट को एक रैपपैनल में सेट कर रहा हूं, जो ऐप का आकार बदलने पर लपेटता प्रतीत नहीं होता है - ऐसा लगता है कि यह एक स्टैकपैनल की तरह व्यवहार करता है। कुल मिलाकर, मुझे लगता है कि रे द्वारा उपरोक्त उत्तर मुझे सही दिशा में ले जाता है। –

+0

मुझे बहुत खुशी है कि मैंने इस पोस्ट में ठोकर खाई, उसने मुझे अपने सभी बालों को खींच लिया। – Bijington

0

कृपया मुझे इस प्रश्न का उत्तर देने के लिए अनुमति दें: क्या उपयोगकर्ता को हर समय सूची में प्रत्येक आइटम के भीतर प्रत्येक थंबनेल देखना होगा?

यदि उस प्रश्न का उत्तर 'नहीं' है, तो शायद आंतरिक आइटम टेम्पलेट के भीतर दृश्यमान पृष्ठों की संख्या को सीमित करना संभव होगा (बशर्ते आपने स्क्रॉलिंग को 5 पृष्ठों के साथ अच्छी तरह से काम किया है) और एक अलग 'चयनित आइटम' टेम्पलेट का उपयोग करें जो बड़ा है और उस दस्तावेज़ के सभी पृष्ठों को प्रदर्शित करता है?बिली होलिस बताते हैं कि कैसे dnrtv पर एक लिस्टबॉक्स में 'पॉप' एक चयनित आइटम बाहर करने के लिए episode 115

+0

कोई उपयोगकर्ता हर समय सूची में हर आइटम के भीतर प्रत्येक और हर थंबनेल देखने के लिए नहीं है - वे बस स्क्रॉल करने के लिए सक्षम होना चाहिए अन्य वस्तुओं को पाने के लिए –

13

.NET 4.5 में अब VirtualizingPanel.ScrollUnit="ScrollUnit" संपत्ति है। मैंने बस अपने ट्री व्यू में से एक को सूची बॉक्स में परिवर्तित कर दिया और प्रदर्शन काफी बेहतर था।

अधिक यहाँ जानकारी: http://msdn.microsoft.com/en-us/library/system.windows.controls.virtualizingpanel.scrollunit(v=vs.110).aspx

36

यह वर्चुअलाइजेशन त्याग करता है, तो आप VirtualizingStackPanel के निजी कार्यक्षमता का उपयोग करने के प्रतिबिंब का उपयोग करने के लिए तैयार हैं बिना WPF 4.0 में आसान स्क्रॉलिंग VirtualizingStackPanels प्राप्त करने के लिए संभव है।आपको बस वर्चुअलाइजिंगस्टैक पैनेल की निजी IsPixelBased संपत्ति को सत्य पर सेट करना है।

ध्यान दें कि .NET 4.5 में इस हैक की कोई आवश्यकता नहीं है क्योंकि आप VirtualizingPanel.ScrollUnit = "पिक्सेल" सेट कर सकते हैं।

public static class PixelBasedScrollingBehavior 
{ 
    public static bool GetIsEnabled(DependencyObject obj) 
    { 
     return (bool)obj.GetValue(IsEnabledProperty); 
    } 

    public static void SetIsEnabled(DependencyObject obj, bool value) 
    { 
     obj.SetValue(IsEnabledProperty, value); 
    } 

    public static readonly DependencyProperty IsEnabledProperty = 
     DependencyProperty.RegisterAttached("IsEnabled", typeof(bool), typeof(PixelBasedScrollingBehavior), new UIPropertyMetadata(false, HandleIsEnabledChanged)); 

    private static void HandleIsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     var vsp = d as VirtualizingStackPanel; 
     if (vsp == null) 
     { 
      return; 
     } 

     var property = typeof(VirtualizingStackPanel).GetProperty("IsPixelBased", 
                    BindingFlags.NonPublic | BindingFlags.Instance); 

     if (property == null) 
     { 
      throw new InvalidOperationException("Pixel-based scrolling behaviour hack no longer works!"); 
     } 

     if ((bool)e.NewValue == true) 
     { 
      property.SetValue(vsp, true, new object[0]); 
     } 
     else 
     { 
      property.SetValue(vsp, false, new object[0]); 
     } 
    } 
} 

एक ListBox पर इस का उपयोग करने के लिए, उदाहरण के लिए, आप क्या करेंगे:

<ListBox> 
    <ListBox.ItemsPanel> 
     <ItemsPanelTemplate> 
     <VirtualizingStackPanel PixelBasedScrollingBehavior.IsEnabled="True"> 
      </VirtualizingStackPanel> 
     </ItemsPanelTemplate> 
    </ListBox.ItemsPanel> 
</ListBox> 
+19

यह वास्तव में सहायक था, +1। भविष्य में आने वाले विज़िटर के लिए .NET 4.5 का उपयोग करके, आपको 'वर्चुअलाइजिंग पैनेल' स्क्रॉलयूनीट = "पिक्सेल" को अपने 'लिस्टबॉक्स' पर सेट करना होगा, न कि 'वर्चुअलाइजिंगस्टैक पैनेल' पर जो सामग्री रखता है। –

+0

ठीक है, यह मेरे लिए काम नहीं करता है। पता नहीं क्यों। –

+0

@ViktorLaCroix: क्या आपने अपनी मशीन पर नेट 4.5 स्थापित किया है? क्योंकि यह .NET 4.0 में एक इन-प्लेस अपडेट है, मुझे लगता है कि यह इस हैक को तोड़ देता है। –

4

यह मेरे लिए काम किया

यह वास्तव में आसान बनाने के लिए, यहाँ कुछ कोड है। लगता सरल विशेषताओं में से एक जोड़े को यह करना होगा (.NET 4,5)

<ListBox    
    ItemsSource="{Binding MyItems}" 
    VirtualizingStackPanel.IsVirtualizing="True" 
    VirtualizingStackPanel.ScrollUnit="Pixel"/> 
संबंधित मुद्दे