2012-03-08 24 views
5

मेरे पास ListView नियंत्रण है जो एक अवलोकन संग्रह से आइटम प्रदर्शित करता है। इन वस्तुओं को फ़िल्टर करने की जरूरत है। मैं इसे CollectionViewSource के साथ करने में सक्षम हूं, लेकिन जब भी कोई आइटम बदलता है तो फ़िल्टर को अद्यतन करने की आवश्यकता होती है।एक अवलोकन संग्रह फ़िल्टर करें

मेरे कपड़े इस तरह दिखता है:

enum Status {Done, Failed, Skipped, ...} 

class Project { 
    public string Name {get;set;} 
    public Status Status {get;set;} 
    // etc. etc. 
} 

class ProjectViewModel : INotifyPropertyChanged { 
    private Project project; 

    public ProjectBuildInfoViewModel(ProjectBuildInfo project) 
    { 
    this.project = project; 
    } 

    public string Name 
    { 
    get { return project.Name; } 
    set { project.Name = value; OnPropertyChanged("Name"); } 
    } 

    // etc. etc. 
} 

class CollectionViewModel { 
    private ObservableCollection<ProjectViewModel> projects = 
      new ObservableCollection<ProjectViewModel>(); 

    public ObservableCollection<ProjectViewModel> Collection 
    { 
    get { return projects; } 
    private set {projects = value; } 
    } 
} 

तब मैं इस ListView जिसका ItemSource संग्रह करने के लिए बाध्य कर रहा है।

// member of the user control class 
private CollectionViewModel collection = new CollectionViewModel(); 

// in the constructor 
listView.ItemSource = collection.Collection. 

यह कुछ भी फ़िल्टर नहीं करता है। तो मेरे पास ये चेक बॉक्स हैं और उन्हें इंगित करना चाहिए कि कौन से आइटम (राज्य के आधार पर) प्रदर्शित किए जाने चाहिए। मैं तो एक CollectionViewSource का इस्तेमाल किया है:

private void UpdateView() 
{ 
    var source = CollectionViewSource.GetDefaultView(collection.Collection); 
    source.Filter = p => Filter((ProjectViewModel)p); 
    listStatus.ItemsSource = source; 
} 

फिल्टर विधि इस तरह दिखता है: मैं इस विधि कॉल करने के लिए है

private bool Filter(ProjectViewModel project) 
{ 
    return (ckFilterDone.IsChecked.HasValue && ckFilterDone.IsChecked.Value && project.Status == Status.Done) || 
      (ckFilterFailed.IsChecked.HasValue && ckFilterFailed.IsChecked.Value && project.Status == Status.Failed) || 
      (ckFilterSkipped.IsChecked.HasValue && ckFilterSkipped.IsChecked.Value && project.Status == Status.Skipped); 
} 

इस नुकसान यह है कि यह चेक बॉक्स के मूल्यों को दर्शाता है, तो (UpdateView) हर बार एक चेकबॉक्स की जांच की जाती है। लेकिन यह काम करता है।

हालांकि, आइटम स्थिति बदलती है और उदाहरण के लिए "किया गया" चेक नहीं किया जाता है, जब कोई आइटम "किया जाता है" में इसे दृश्य से हटा दिया जाना चाहिए। जाहिर है कि जब तक मैं फिर से UpdateView पर कॉल नहीं करता तब तक यह नहीं बदलेगा। तो मुझे प्रत्येक बार कुछ बदलावों को बदलने के लिए इस विधि को कॉल करने की आवश्यकता है। यह बदसूरत और अक्षम है मुझे लगता है।

तो मेरा सवाल यह है कि, क्या यह एक अच्छे तरीके से किया जा सकता है?

+0

मैंने एक उत्तर के रूप में एक और दृष्टिकोण पोस्ट किया लेकिन मुझे याद है कि फ़िल्टर को अपडेट() के बिना कॉल किए बिना काम करना है। परियोजना में परिवर्तन किए गए NotifyProperty को लागू करने का प्रयास करें - बाध्यकारी इसके बिना किसी बदलाव के बारे में पता नहीं है। – Paparazzi

उत्तर

13

फ़िल्टर्ड संग्रह ObservableCollection के बजाय सीधे अपने ListView बाइंड एक प्रॉपर्टी बनाकर -

public ICollectionView YourFilteredCollection 
{ 
    get 
    {  
     var source = CollectionViewSource.GetDefaultView(collection.Collection); 
     source.Filter = p => Filter((ProjectViewModel)p); 
     return source; 
    } 
} 

तो, अब बस आप अपने चेक बॉक्स राज्य पर अपना संकलन पर ताज़ा() कॉल करने की आवश्यकता इस तरह बदली हुई घटना -

YourFilteredCollection.Refresh(); 

आइटम कक्षा में किसी भी राज्य परिवर्तन के आधार पर संग्रह को ताज़ा करने के लिए, आप hooking द्वारा यह सामान्यीकरण कर सकते हैं जब भी अपने मद कक्षा में किसी भी संपत्ति में परिवर्तन, अपने संग्रह फ़िल्टर कर दिया जाएगा,

foreach (YourClass item in collection.Collection) 
{ 
    item.PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged); 
} 

void item_PropertyChanged(object sender, PropertyChangedEventArgs e) 
{ 
    YourFilteredCollection.Refresh(); 
} 

तो - अपने मद वर्ग के PropertyChanged घटना और वहाँ से आप इस तरह ताज़ा कॉल कर सकते हैं (यह अपनी कक्षा के लिए INotifyPropertyChanged लागू करने की आवश्यकता) ।

+1

लेकिन मुझे अभी भी किसी आइटम की स्थिति, या चेक बॉक्स बदलना ताज़ा करना होगा। –

+0

मैंने राज्य परिवर्तन के लिए आपकी चिंता के संबंध में अपना उत्तर अपडेट किया है।तो इस तरह आपको केवल दो स्थानों से ताज़ा करने की आवश्यकता है। उम्मीद है की यह मदद करेगा। इसके अलावा, आप पर्यवेक्षण चयन को उपclass कर सकते हैं और इस तर्क को वहां ले जा सकते हैं और अपने पर्यवेक्षण चयन के स्थान पर अपने उप-वर्गों का उपयोग कर सकते हैं। –

+1

यह पर्यवेक्षण चयन को उपclass करने में आपकी सहायता का हो सकता है - http://msdn.microsoft.com/en-us/library/ee696421.aspx –

4

मुझे इसके लिए डेटाट्रिगर्स का उपयोग करना पसंद है। आपके तर्क के लिए एक बहुविकल्पीय कनवर्टर का उपयोग करने की आवश्यकता होगी।

<ListView Grid.Row="3" Grid.Column="2" ItemsSource="{Binding Path=GabeLib.DocFieldsAll}"> 
     <ListView.ItemContainerStyle> 
      <Style TargetType="{x:Type ListViewItem}" > 
       <Style.Triggers> 
        <DataTrigger Binding="{Binding Path=Active}" Value="False"> 
         <Setter Property="Visibility" Value="Collapsed"/> 
        </DataTrigger> 
        <DataTrigger Binding="{Binding Path=FieldDef.ID}" Value="0"> 
         <Setter Property="Visibility" Value="Collapsed"/> 
        </DataTrigger> 
       </Style.Triggers> 
      </Style> 
     </ListView.ItemContainerStyle> 
1

ContinuousLinq जैसे टूल का उपयोग करें। आप अपनी सूचीदृश्य को उस क्वेरी पर बाध्य करते हैं जो सूची में कोई आइटम (या सूची स्वयं) बदलता है, फिर से मूल्यांकन करेगा।

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