2009-05-13 10 views
11

मेरे पास एक WPF ListBoxObservableCollection से जुड़ा हुआ है। जब संग्रह में चीजें जोड़ दी जाती हैं, तो ListBox अतिरिक्त प्रविष्टियों के आकार से स्क्रॉल स्थिति बदल जाती है। मैं स्क्रॉल स्थिति को संरक्षित करने में सक्षम होना चाहता हूं, ताकि सूची में चीजें जोड़े जाने के बावजूद, वर्तमान में देखे जाने वाले आइटम स्थानांतरित नहीं होते हैं। क्या इसको मदद देने का कोई तरीका है?संग्रह बदलते समय एक बाध्य WPF ListBox की स्क्रॉल स्थिति को संरक्षित करते हुए

+0

मैंने अभी तक एक सूची बॉक्स में एक बहुत ही सरल wpf डेटाबेसिंग किया है और जब मैं आइटम जोड़ता हूं तो दृश्यों को ध्यान में रखा गया था ... आप और क्या कर रहे हैं? – TheCodeMonk

+0

संग्रह की बड़ी संख्या में नए आइटम जोड़ने का प्रयास करें। जिन आइटमों को आप देख रहे हैं वे व्यूपोर्ट से बाहर निकलते हैं क्योंकि नए आइटम जोड़े जाते हैं। आप 1 आइटम जोड़ते हैं - व्यूपोर्ट एक ही स्थिति (इंडेक्स-आधारित) पर रहता है जिसका अर्थ है कि 1 आइटम व्यूपोर्ट में प्रवेश करता है और 1 आइटम इसे छोड़ देता है। – EvAlex

उत्तर

0

मुझे यकीन नहीं है कि इसके लिए ओवरराइड है, लेकिन मुझे शक है।

जब संदेह में मैन्युअल बाध्यकारी उपयोग किया जाता है? : -} गंभीरता से, डिफ़ॉल्ट बाध्यकारी व्यवहार - अच्छी तरह से डिफ़ॉल्ट होगा, इसलिए यदि आपको विशेष व्यवहार मैन्युअल बाध्यकारी की आवश्यकता है तो बेहतर विकल्प है। मैन्युअल बाध्यकारी के साथ आप स्क्रॉल स्थिति को सहेज सकते हैं और आइटम जोड़ने के बाद इसे रीसेट कर सकते हैं।

+0

जो एक स्पष्ट प्रश्न की ओर जाता है - मैं वर्तमान स्क्रॉल स्थिति कैसे निर्धारित करूं? –

1

संग्रह दृश्य बनाएं। इस प्रयास करें:

private ObservableCollection<int> m_Values; 
    private CollectionView m_View; 

    private void Bind() 
    { 
     m_Values = new ObservableCollection<int>(); 
     m_View = new CollectionView(m_Values); 
     MyListBox.ItemsSource = m_View; 
    } 

    private void MyListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) 
    { 
     Debug.WriteLine(m_View.CurrentItem); 
     Debug.WriteLine(m_View.CurrentPosition); 
    } 
+1

कृपया आगे की व्याख्या करें। यह उत्तर समस्या को हल करने के लिए प्रतीत नहीं होता है - यह केवल वर्तमान आइटम और स्थिति की रिपोर्ट करता है। मुझे एक वर्चुअलिंगस्टैकपैनल पर सेट किए गए आइटम्सपैनल के साथ एक सूची बॉक्स का उपयोग करके एक ही समस्या है। समस्या यह है कि मैं इसे देखता हूं कि सूची बॉक्स आइटम आगे बढ़ते रहते हैं क्योंकि नए आइटम अवलोकन संग्रह में जोड़े जाते हैं। हालांकि वस्तुओं को वापस ले जाना संभव है जहां वे एक नए आइटम के बाद थे (उदा।, चयनित इंडेक्स का उपयोग करके), यह एक झटकेदार गति बनाता है। स्क्रॉल की स्थिति को पहले स्थान पर बदलने से रोकने के लिए जरूरी चीज है क्योंकि नए आइटम जोड़े जाते हैं। – CyberMonk

+0

मुझे एक ही समस्या है, लेकिन आपका समाधान मानता है कि somethig का चयन किया गया है। लेकिन क्या होगा यदि उपयोगकर्ता कुछ भी चुनना नहीं चाहता? बस कहीं स्क्रॉल करें और इसे छोड़ दें। – EvAlex

0

जब चीजें जोड़ रहे हैं आप नियंत्रित करते हैं? मेरा मतलब है कि आपके पास एक या दो परिभाषित बिंदु हैं जहां डेटा बदल जाता है? यदि ऐसा है, तो एक आसान समाधान (शायद सुरुचिपूर्ण नहीं) तो स्थानीय सूची चर को वर्तमान सूची बॉक्स को पकड़ने के लिए होगा। चयनित Index। डेटा परिवर्तन से ठीक पहले, चयनित इंडेक्स को इस चर में सहेजें और डेटा जोड़े जाने के बाद, सूची के चयनित इंडेक्स को इस चर के मान पर सेट करें।

1

सबसे पहले सूचीबॉक्स द्वारा चयनित स्थिति पाएं। चयन किए गए इंडेक्स और फिर ListBox.ScrollIntoView (/ * वर्तमान अनुक्रमणिका * /) का उपयोग करें। भले ही नए आइटम सूची में जोड़े गए हों, आपकी वर्तमान स्थिति और दृश्य वही होगा।

3

मुझे एक ही समस्या का सामना करना पड़ा और एक और प्रतिबंध: उपयोगकर्ता आइटम का चयन नहीं करता है, बल्कि केवल स्क्रॉल करता है। यही कारण है कि ScrollIntoView() विधि बेकार है। मेरा समाधान यहाँ है।

पहले, मैं DependencyObject से पाने, प्रकार bool के एक संलग्न निर्भरता संपत्ति PreserveScroll साथ वर्ग ScrollPreserver बनाया:

public class ScrollPreserver : DependencyObject 
{ 
    public static readonly DependencyProperty PreserveScrollProperty = 
     DependencyProperty.RegisterAttached("PreserveScroll", 
      typeof(bool), 
      typeof(ScrollPreserver), 
      new PropertyMetadata(new PropertyChangedCallback(OnScrollGroupChanged))); 

    public static bool GetPreserveScroll(DependencyObject invoker) 
    { 
     return (bool)invoker.GetValue(PreserveScrollProperty); 
    } 

    public static void SetPreserveScroll(DependencyObject invoker, bool value) 
    { 
     invoker.SetValue(PreserveScrollProperty, value); 
    } 

    ... 
} 

संपत्ति बदल कॉलबैक मान लिया गया संपत्ति ScrollViewer द्वारा निर्धारित है। कॉलबैक विधि निजी शब्दकोश को यह ScrollViewer कहते हैं और इसे करने के लिए ScrollChanged ईवेंट हैंडलर जोड़ता है:

private static Dictionary<ScrollViewer, bool> scrollViewers_States = 
    new Dictionary<ScrollViewer, bool>(); 

private static void OnScrollGroupChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
{ 
    ScrollViewer scrollViewer = d as ScrollViewer; 
    if (scrollViewer != null && (bool)e.NewValue == true) 
    { 
     if (!scrollViewers_States.ContainsKey(scrollViewer)) 
     { 
      scrollViewer.ScrollChanged += new ScrollChangedEventHandler(scrollViewer_ScrollChanged); 
      scrollViewers_States.Add(scrollViewer, false); 
     } 
    } 
} 

इस शब्दकोश अनुप्रयोग में सभी ScrollViewers कि इस वर्ग का उपयोग करने के संदर्भ का आयोजन करेगा। मेरे मामले में आइटम संग्रह की शुरुआत में जोड़े गए हैं। समस्या यह है कि व्यूपोर्ट स्थिति बदलती नहीं है। यह ठीक है जब स्थिति 0 है: व्यूपोर्ट में पहला तत्व हमेशा पहला आइटम होगा। लेकिन जब व्यूपोर्ट में पहले तत्व में 0 से अधिक इंडेक्स होता है और नए आइटम जोड़े जाते हैं - उस तत्व की अनुक्रमणिका बढ़ जाती है तो यह नीचे स्क्रॉल हो जाती है। तो bool मूल्य 0. यह दर्शाता है कि ScrollViewer खड़ी की ऑफसेट है नहीं अगर यह 0 है कुछ भी करने को कोई जरूरत नहीं है, और अगर यह 0 नहीं है, यह व्यूपोर्ट में आइटम में अपनी स्थिति बनाए रखने के लिए आवश्यक है:

static void scrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e) 
{ 
    if (scrollViewers_States[sender as ScrollViewer]) 
     (sender as ScrollViewer).ScrollToVerticalOffset(e.VerticalOffset + e.ExtentHeightChange); 

    scrollViewers_States[sender as ScrollViewer] = e.VerticalOffset != 0; 
} 

अतिरिक्त आइटम की मात्रा को इंगित करने के लिए ExtentHeightChange का उपयोग यहां किया जाता है। मेरे मामले में आइटम केवल संग्रह की शुरुआत में जोड़े जाते हैं, इसलिए मुझे इस मूल्य से स्क्रॉलव्यूयर के वर्टिकल ऑफसेट को बढ़ाने की ज़रूरत है। और आखिरी बात: उपयोग। लिस्टबॉक्स के लिए यहां उदाहरण दिया गया है:

<Listbox ...> 
    <ListBox.Resourses> 
     <Style TargetType="ScrollViewer"> 
      <Setter Property="local:ScrollPreserver.PreserveScroll" Value="True" /> 
     </Style> 
    </ListBox.Resourses> 
</ListBox> 

ता-दा!अच्छा काम करता है :)

+0

क्या स्थैतिक क्षेत्र में शब्दकोश की वजह से यह स्मृति लीक नहीं है? – TcKs

+0

निर्भरता प्रॉपर्टीज सभी स्थिर हैं। उदाहरण के लिए आप इसके बारे में यहां पढ़ सकते हैं: http://stackoverflow.com/questions/2989431/why-are- निर्भरता-properties-static – EvAlex

+0

मुझे पता है। लेकिन "scrollViewers_States" फ़ील्ड निर्भरता संपत्ति के लिए शॉर्टकट नहीं है। यह स्क्रॉलव्यूअर के उदाहरणों को संग्रहीत करता है। क्या आपके पास कुछ कोड है जो शब्दकोश से पुरानी घटनाओं को हटा देता है? – TcKs

संबंधित मुद्दे