2017-05-11 80 views
0

我想濾波器,用於過濾我多列和多過濾器的ListView,但我不得到一個知道如何...篩選多個列的ListView C#WPF

enter image description here

這是我的想法:一個窗口這顯示當前選擇的 列標題,您可以在下拉菜單中選擇=或>並與你的標準,然後過濾,我只找到一列,但多過濾器不知道的解決方案......

數據負載:

var xdoc = XDocument.Load(@"C:\temp\webTsl.xml"); 
       var units = from u in xdoc.Descendants("sl") 
          select new 
          { 
           EQNr = (string)u.Element("id"), 
           //EQCore = (string)u.Element(""), 
           ArtNr = (string)u.Element("artNr"), 
           Bez = (string)u.Element("bez"), 
           //KundenBez = (string)u.Element(""), 
           //ProjektNr = (string)u.Element(""), 
           //LiefDat = (DateTime)u.Element(""), 
           //EqStart = (DateTime)u.Element(""), 
           //GewaehrStart = (DateTime)u.Element(""), 
           //GewaehrEnde = (DateTime)u.Element("") 
          }; 

       foreach (var unit in units) 
       { 
        items.Add(new Anlagen(unit.EQNr, unit.ArtNr, unit.Bez)); 
       } 


      ListViewAnlagen.ItemsSource = CollectionViewSource.GetDefaultView(items); 

類:

public virtual string EQNr { get; set; } 
     //public virtual string EQCore { get; set; } 
     public virtual string ArtNr { get; set; } 
     public virtual string Bez { get; set; } 
     //public virtual string KundenBez { get; set; } 
     //public virtual string ProjektNr { get; set; } 
     //public virtual DateTime? LiefDat { get; set; } 
     //public virtual DateTime? EqStart { get; set; } 


     //public virtual DateTime? GewaehrStart { get; set; } 
     //public virtual DateTime? GewaehrEnde { get; set; } 

     public Anlagen(string eqNr,string artNr, string bez) /*, DateTime liefdat, DateTime inbetnahme,DateTime garantiestart,DateTime garantieende*/ 
     { 
      this.EQNr = eqNr; 
      //this.EQCore = eqCore; 
      this.ArtNr = artNr; 
      this.Bez = bez; 
      //this.KundenBez = kundenBez; 
      //this.ProjektNr = projektNr; 
      //this.LiefDat = liefDat; 
      //this.EqStart = eqStart; 
      //this.GewaehrStart = gewaehrStart; 
      //this.GewaehrEnde = gewaehrEnde; 

     } 

     public Anlagen() 
     { 
    } 

回答

0

基本上,你需要一個過濾器定義,在您的項目中傳遞和一個特定的列過濾功能決定項目是否滿足過濾器。

比方說你有一個過濾器界面如下:

public interface IFilterBase<TItem> 
{ 
    PropertyInfo Property { get; } // can be used to display the property name etc. 

    bool ApplyFilter(T value); 
} 

和像

public class StringContainsFilter<TItem> : IFilterBase<TItem> 
{ 
    public StringContainsFilter(PropertyInfo prop) 
    { 
     // TODO Requirements to check: 
     // typeof(TItem).IsAssignableFrom(prop.DeclaringType) 
     // typeof(string).IsAssignableFrom(prop.PropertyType) 
    } 

    // TODO Property getter implementation 

    public string ContainedText { get; set; } // TODO INotifyPropertyChanged 

    public bool ApplyFilter(TItem value) 
    { 
     // get the property value via reflection and check against the contains filter condition 
     var text = Property.GetValue(value) as string ?? ""; 
     return text.Contains(ContainedText ?? ""); 
    } 
} 

Ofcourse一些實現,你必須定義過濾器實現你真正想要的過濾,支持一切(財產類型和操作)。

因此,基本上,對於每一列,您都會根據屬性類型決定支持的過濾器,並讓用戶選擇過濾器並輸入標準。

仍然是如何運用一系列的過濾器的問題......讓假設用戶輸入一些過濾條件,並在集合中保存的每個過濾器,如:

ObservableCollection<IFilterBase<TItem>> Filters; 

然後充分收集的物品可以變成過濾收集的物品,如:

source.Where(item => Filters.All(filter => filter.ApplyFilter(item))) 

爲了有一個項目MVVM準備過濾收集,我用下面的輔助類,在我的項目之一:

public class ObservableLinq<TIn, TOut> : IEnumerable<TOut>, INotifyCollectionChanged 
{ 
    private ObservableCollection<TIn> _Source; 
    private Func<IEnumerable<TIn>, IEnumerable<TOut>> _Transformation; 

    public ObservableLinq(ObservableCollection<TIn> source, Func<IEnumerable<TIn>, IEnumerable<TOut>> transformation) 
    { 
     _Source = source; 
     _Transformation = transformation; 
     _Source.CollectionChanged += Source_CollectionChanged; 
    } 

    public ObservableLinq(IEnumerable<TIn> source, Func<IEnumerable<TIn>, IEnumerable<TOut>> transformation) 
     : this(source as ObservableCollection<TIn> ?? new ObservableCollection<TIn>(source), transformation) 
    { 
    } 

    private void Source_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) 
    { 
     RaiseCollectionChanged(); 
    } 

    public IEnumerator<TOut> GetEnumerator() 
    { 
     return _Transformation(_Source).GetEnumerator(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 


    // could be a property as well, but this empathizes, that the source collection is not the primary functionality here 
    public ObservableCollection<TIn> GetSourceCollection() 
    { 
     return _Source; 
    } 


    public event NotifyCollectionChangedEventHandler CollectionChanged; 

    protected void RaiseCollectionChanged() 
    { 
     var handler = CollectionChanged; 
     if (handler != null) 
     { 
      // always reset as it would be pretty complicated to track the actual changes across all the linq thingies 
      handler(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); 
     } 
    } 

    /// <summary> 
    /// Call when a filter relevant property changed on source collection entries 
    /// </summary> 
    public void CollectionChangedNeeded() 
    { 
     RaiseCollectionChanged(); 
    } 
} 

用法:

public ObservableLinq<TItem, TItem> FilteredItems { get {...} set {...} } 

// init: 
FilteredItems = new ObservableLinq<TItem, TItem>(ItemsList, source.Where(item => Filters.All(filter => filter.ApplyFilter(item)))); 

然後,當項集合的變化,一個項目屬性發生變化時,有源濾波器集合改變或濾波器特性的變化,觸發過濾項的更新(項集合的變化採取醫療服務時的源集合是ObservableCollection的)

FilteredItems.CollectionChangedNeeded(); 

我覺得這種方法比使用內置的WPF的過濾器功能提供的控件更加靈活。基於正則表達式的過濾器,自定義屬性類型的過濾器......所有可能的過濾器類型都沒有太大影響。只是過濾基礎設施的初始設置並不十分簡單。

+0

我可以問你一個例子嗎? –

+0

先生,我試着理解你的解決方案,但我不明白,你可以舉個例子嗎? –

+0

也許我可以寫一個,不是現在......正如你可以從片段中看到的,一個準備好的例子需要幾行代碼和xaml。 – grek40