2012-06-21 8 views
25

मैं एक WPF एप्लिकेशन बना रहा हूं जो कस्टम "अगला" और "बैक" बटन और कमांड (यानी NavigationWindow का उपयोग नहीं कर रहा है) के माध्यम से नेविगेट करने योग्य है। एक स्क्रीन पर, मेरे पास ListBox है जिसे एकाधिक चयनों का समर्थन करना है (Extended मोड का उपयोग करके)। मेरे पास इस स्क्रीन के लिए एक व्यू मॉडल है और चयनित आइटम को एक संपत्ति के रूप में स्टोर करें, क्योंकि उन्हें बनाए रखने की आवश्यकता है।सूची बॉक्स का चयन कैसे करें IVVM के साथ बाध्यकारी एक नेविगेशन अनुप्रयोग

हालांकि, मुझे पता है कि SelectedItemsListBox की संपत्ति केवल पढ़ने योग्य है। मैं this solution here का उपयोग कर इस मुद्दे के आसपास काम करने की कोशिश कर रहा हूं, लेकिन मैं इसे अपने कार्यान्वयन में अपनाने में सक्षम नहीं हूं। मैंने पाया कि जब मैं एक या अधिक तत्वों को अचयनित करता हूं और जब मैं स्क्रीन के बीच नेविगेट करता हूं तो मैं अलग-अलग नहीं हो सकता (NotifyCollectionChangedAction.Remove दोनों मामलों में उठाया जाता है, क्योंकि तकनीकी रूप से सभी चयनित आइटम स्क्रीन से दूर नेविगेट करते समय अचयनित होते हैं)। मेरे नेविगेशन कमांड एक अलग दृश्य मॉडल में स्थित हैं जो प्रत्येक स्क्रीन के लिए दृश्य मॉडल प्रबंधित करता है, इसलिए मैं दृश्य मॉडल से संबंधित ListBox के साथ कोई कार्यान्वयन नहीं कर सकता।

मुझे कई अन्य कम सुरुचिपूर्ण समाधान मिल गए हैं, लेकिन इनमें से कोई भी दृश्य मॉडल और दृश्य के बीच दो-तरफा बाध्यकारी प्रथा प्रतीत नहीं होता है।

किसी भी मदद की सराहना की जाएगी। अगर मैं अपनी समस्या को समझने में मदद करता हूं तो मैं अपना कुछ स्रोत कोड प्रदान कर सकता हूं।

+0

आह, मैं देखता हूं, आप पहले से ही एक व्यवहार का उपयोग करने का प्रयास कर रहे हैं। चयनित वस्तुओं के लिए एक बाइंडेबल कोलेक्शन का उपयोग करें, इसे काम करना चाहिए। यदि आपको और समस्याएं हैं, तो बस मुझे बताएं। उनका वर्णन करें और हम एक नज़र डालेंगे। –

+1

कृपया कुछ कोड दिखाएं, खासकर चयनित इटम्स और एक्सएएमएल। क्या चुना गया एक संपत्ति है? उस व्यवहार पर संदेह करें जब चयनित इटम्स केवल बाइंडबल कोलेक्शन का सार्वजनिक सदस्य था, संपत्ति नहीं। –

+1

आह, मुझे एहसास नहीं हुआ कि संपत्ति को स्पष्ट रूप से 'चयनित इटम्स' कहा जाना था (मेरा 'चयनित भाषाएं' कहा जाता था)। अब जब मैं 'RaisePropertyChangedEventHandler'' के साथ प्रेषक लाइन पर "बैक" बटन पर क्लिक करता हूं, तो मुझे 'बाइंडेबल कोलेक्शन' कन्स्ट्रक्टर में फेंक दिया गया 'अमान्यऑपरेशन अपवाद' मिलता है। मैंने कैच ब्लॉक में 'डिस्पैचर.बिनजिन इनवोक' के साथ एक कोशिश/पकड़ ब्लॉक डालने की कोशिश की, लेकिन तब पृष्ठ को फिर से चुना नहीं जाता है जब पृष्ठ पर नेविगेट किया जाता है। – Casey

उत्तर

41

अपने डेटा वस्तुओं में से प्रत्येक पर एक IsSelected संपत्ति बनाने और उस संपत्ति को ListBoxItem.IsSelected बाध्यकारी

<Style TargetType="{x:Type ListBoxItem}"> 
    <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" /> 
</Style> 
+0

मेरी 'लिस्टबॉक्स' में 'संस्कृतिइन्फो' आइटम शामिल हैं, तो क्या 'संस्कृतिइन्फो' से प्राप्त एक कस्टम क्लास के बिना आपके समाधान का उपयोग करना संभव होगा और 'IsSelected' संपत्ति' हो? या क्या मैं आपके समाधान को गलत तरीके से समझ रहा हूं? – Casey

+0

@ user1463765 नहीं, आपको – Rachel

+0

ठीक काम करने के लिए आपके ऑब्जेक्ट पर 'IsSelected' प्रॉपर्टी' रखना होगा, धन्यवाद। मैं पहले एक व्यवहार का उपयोग कर अपनी समस्या को हल करने की कोशिश करने जा रहा हूं, क्योंकि मैं एक कस्टम वर्ग को परिभाषित करने से बचाना पसंद करूंगा। अगर मैं काम करने का व्यवहार नहीं कर पाता हूं तो मैं निश्चित रूप से आपके समाधान का प्रयास करूंगा। – Casey

16

रेचेल के समाधान का प्रयास करें महान काम करता है! लेकिन मुझे एक समस्या आई है - यदि आप ListBoxItem की शैली को ओवरराइड करते हैं, तो आप उस पर लागू मूल स्टाइल को खो देते हैं (मेरे मामले में चयनित आइटम इत्यादि को हाइलाइट करने के लिए ज़िम्मेदार)। आप मूल शैली से इनहेरिट द्वारा इससे बचने कर सकते हैं:

<Style TargetType="{x:Type ListBoxItem}" BasedOn="{StaticResource {x:Type ListBoxItem}}"> 
    <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" /> 
</Style> 

नोट BasedOn की स्थापना (देखें this answer) ।

8

मुझे यह काम करने के लिए राहेल का समाधान नहीं मिला, लेकिन मुझे Sandesh's कस्टम dependency property बनाने के उत्तर को मेरे लिए पूरी तरह से काम करने के लिए मिला। मुझे बस एक सूची बॉक्स के लिए समान कोड लिखना पड़ा:

public class ListBoxCustom : ListBox 
{ 
    public ListBoxCustom() 
    { 
     SelectionChanged += ListBoxCustom_SelectionChanged; 
    } 

    void ListBoxCustom_SelectionChanged(object sender, SelectionChangedEventArgs e) 
    { 
     SelectedItemsList = SelectedItems; 
    } 

    public IList SelectedItemsList 
    { 
     get { return (IList)GetValue(SelectedItemsListProperty); } 
     set { SetValue(SelectedItemsListProperty, value); } 
    } 

    public static readonly DependencyProperty SelectedItemsListProperty = 
     DependencyProperty.Register("SelectedItemsList", typeof(IList), typeof(ListBoxCustom), new PropertyMetadata(null)); 

} 

मेरे व्यू मॉडल में मैंने बस अपनी चुनी सूची प्राप्त करने के लिए उस संपत्ति का संदर्भ दिया।

+0

मुझे यह जवाब पसंद है, लेकिन मैं शायद कोड को ट्वीक कर दूंगा: https://pastebin.com/YTccwmxG – maxp

-1

IsSelected संपत्ति में चेक बॉक्स को बाध्य करना बंद कर देता है और स्टैक पैनल के भीतर टेक्स्टब्लॉक और चेकबॉक्स डालकर चाल करता है!

1

मैं इसके लिए एक आसान समाधान देख रहा था लेकिन बिना किसी किस्मत के।

समाधान राहेल अच्छा है यदि आपके पास पहले से ही आपके आइटम स्रोत में ऑब्जेक्ट पर चयनित संपत्ति है। यदि आप नहीं करते हैं, तो आपको उस व्यवसाय मॉडल के लिए एक मॉडल बनाना होगा।

मैं एक अलग मार्ग चला गया। एक त्वरित, लेकिन सही नहीं है।

अपनी सूची बॉक्स पर चयन चयन के लिए एक ईवेंट बनाएं।

<ListBox ItemsSource="{Binding SomeItemsSource}" 
     SelectionMode="Multiple" 
     SelectionChanged="lstBox_OnSelectionChanged" /> 

अब अपने XAML पृष्ठ के पीछे कोड पर ईवेंट लागू करें।

private void lstBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e) 
{ 
    var listSelectedItems = ((ListBox) sender).SelectedItems; 
    ViewModel.YourListThatNeedsBinding = listSelectedItems.Cast<ObjectType>().ToList(); 
} 

ताडा। किया हुआ।

यह converting SelectedItemCollection to a List की सहायता से किया गया था।

0

दिए गए उत्तरों से संतुष्ट नहीं मैं अपने आप को खोजने की कोशिश कर रहा था ... वैसे यह एक हैक की तरह अधिक है, लेकिन एक समाधान है लेकिन मेरे लिए यह ठीक काम करता है। यह समाधान मल्टीबिंडिंग का एक विशेष तरीके से उपयोग करता है। सबसे पहले यह कोड के एक टन की तरह लग सकता है लेकिन आप इसे बहुत कम प्रयास के साथ पुन: उपयोग कर सकते हैं।

public class SelectedItemsContainer 
{ 
    /// Nothing special here... 
    public object SelectedItems { get; set; } 
} 

अब हम हमारी ListBox.SelectedItem (एकवचन) के लिए बाध्यकारी बनाने के लिए:

सबसे पहले मैं एक 'IMultiValueConverter'

public class SelectedItemsMerger : IMultiValueConverter 
{ 
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 
    { 
     SelectedItemsContainer sic = values[1] as SelectedItemsContainer; 

     if (sic != null) 
      sic.SelectedItems = values[0]; 

     return values[0]; 
    } 

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 
    { 
     return new[] { value }; 
    } 
} 

और एक SelectedItems कंटेनर/आवरण को लागू किया। नोट: आपको 'कनवर्टर' के लिए एक स्थिर संसाधन बनाना होगा। यह प्रति आवेदन एक बार किया जा सकता है और सभी सूची बॉक्सों के लिए पुन: उपयोग किया जा सकता है जिन्हें कनवर्टर की आवश्यकता होती है।

<ListBox.SelectedItem> 
<MultiBinding Converter="{StaticResource SelectedItemsMerger}"> 
    <Binding Mode="OneWay" RelativeSource="{RelativeSource Self}" Path="SelectedItems"/> 
    <Binding Path="SelectionContainer"/> 
</MultiBinding> 
</ListBox.SelectedItem> 

व्यूमोडेल में मैंने कंटेनर बनाया जहां मैं बांध सकता हूं। मूल्यों को भरने के लिए इसे नए() के साथ प्रारंभ करना महत्वपूर्ण है।

SelectedItemsContainer selectionContainer = new SelectedItemsContainer(); 
    public SelectedItemsContainer SelectionContainer 
    { 
     get { return this.selectionContainer; } 
     set 
     { 
      if (this.selectionContainer != value) 
      { 
       this.selectionContainer = value; 
       this.OnPropertyChanged("SelectionContainer"); 
      } 
     } 
    } 

और यही वह है। शायद कोई कुछ सुधार देखता है? आप इसके बारे में क्या सोचते हैं?

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