实现与约什 - 史密斯的WPF MVVM演示应用一个ListView过滤器 [英] Implementing a ListView Filter with Josh Smith's WPF MVVM Demo App

查看:175
本文介绍了实现与约什 - 史密斯的WPF MVVM演示应用一个ListView过滤器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在努力,以更好地了解它背后的校长,扩大约什·史密斯的演示MVVM应用程序,我已经打了试图实现使用一个ListView视图过滤功能时,一堵墙。

我已经花了几个小时研究和涉猎,但它只是不工作。

我的第一个步骤是在我看来,一个文本框绑定到我的视图模型属性:

 <文本框高度=25NAME =txtFilterWIDTH =150文本={绑定路径=过滤,UpdateSourceTrigger =的PropertyChanged}/>

这在我的VM相匹配:

 公共字符串过滤器
    {
        {返回this.filter; }
        组
        {
            this.filter =价值;
            OnFilterChanged();
        }
    }

我的虚拟机使用的数据源一的ObservableCollection,但我试图将其转换为ICollectionView看完教程后:

 内部的ObservableCollection< StaffViewModel> InnerStaff {搞定;组; }
    内部CollectionViewSource CvsStaff {搞定;组; }
    公众的ICollectionView AllStaff
    {
        {返回CvsStaff.View; }
    }

在我的构造函数中我已指定

  CvsStaff =新CollectionViewSource();
CvsStaff.Source = this.InnerStaff;
CvsStaff.Filter + =在applyFilter;

在我的筛选器属性得到更新它调用OnFilterChanged是:

 私人无效OnFilterChanged()
    {
        CvsStaff.View.Refresh();
    }

我在applyFilter功能是:

 无效在applyFilter(对象发件人,FilterEventArgs E)
    {
        StaffViewModel SVM =(StaffViewModel)e.Item;        如果(this.Filter.Length == 0)
        {
            e.Accepted = TRUE;
        }
        其他
        {
            e.Accepted = svm.LastName.Contains(过滤器);
        }
    }

有没有办法,我做了任何人都可以帮助我发现了一个愚蠢的错误?我是相当新的WPF和MVVM模式,所以我还在学习!

修改

在查看我的收藏绑定:

 < CollectionViewSource
  X:键=StaffGroup
  来源={绑定路径= AllStaff}
  />

和ListView控件是这样的:

 < ListView控件
      NAME =staffList
      AlternationCount =2
      的DataContext ={StaticResource的StaffGroup}
      ItemContainerStyle ={StaticResource的StaffItemStyle}
      的ItemsSource ={结合}
        Grid.Row =1>


解决方案

绑定不正确。你需要做一些修改。第一件事情就是要确保在DataContext设置正确。通常情况下你会做这样的ListView中的父母,而不是直接将其置于ListView控件。这可能是一个用户控件/窗/等。

所以,假设你有一个视图模型:

 公共类MainViewModel
{
    公共MainViewModel()
    {
        //创建一些假数据
        InnerStaff =新的ObservableCollection< StaffViewModel>();
        InnerStaff.Add(新StaffViewModel {名字=苏,姓氏=巴克内尔});
        InnerStaff.Add(新StaffViewModel {名字=詹姆斯,姓氏=巴克内尔});
        InnerStaff.Add(新StaffViewModel {名字=约翰,姓氏=哈罗德});        CvsStaff =新CollectionViewSource();
        CvsStaff.Source = this.InnerStaff;
        CvsStaff.Filter + =在applyFilter;
    }    私人字符串过滤器;    公共字符串过滤器
    {
        {返回this.filter; }
        组
        {
            this.filter =价值;
            OnFilterChanged();
        }
    }    私人无效OnFilterChanged()
    {
        CvsStaff.View.Refresh();
    }    内部的ObservableCollection< StaffViewModel> InnerStaff {搞定;组; }
    内部CollectionViewSource CvsStaff {搞定;组; }
    公众的ICollectionView AllStaff
    {
        {返回CvsStaff.View; }
    }    无效在applyFilter(对象发件人,FilterEventArgs E)
    {
        StaffViewModel SVM =(StaffViewModel)e.Item;        如果(string.IsNullOrWhiteSpace(this.Filter)|| this.Filter.Length == 0)
        {
            e.Accepted = TRUE;
        }
        其他
        {
            e.Accepted = svm.LastName.Contains(过滤器);
        }
    }
}

和假设你有一个窗口MainWindow.cs(code后面),你可以(在这个例子中)在此挂钩的DataContext的。

 公共部分类主窗口:窗口
{
    公共主窗口()
    {
        的InitializeComponent();
        的DataContext =新MainViewModel();
    }
}

然后,你必须为你做一个绑定几个选择,你可以在XAML或code指定CollectionViewSource,但你做了两个。即XAML之一,主要X:键=StaffGroup和虚拟机则CvsStaff。比方说,我们摆脱了XAML之一,完全和使用VM之一,这是正确设置。这样,你会使用绑定ItemsSource属性,像这样:

 < ListView控件名称=staffList
      AlternationCount =2
      的ItemsSource ={结合AllStaff}
      Grid.Row =1/>

也小的事情,我已经改变了过滤器来检查空值和空白。您可能还需要将其更改为不区分大小写。

这是我在这里没有提及,但至关重要的是另一件事情是要落实在你的StaffViewModel INotifyPropertyChanged的 - 我假设你有,如果不是这里的一些code。你通常也做到这一点大多数视图模型,将更改通知到性能视图。

 内部类StaffViewModel:INotifyPropertyChanged的
{
    私人字符串_FirstName;
    公共字符串名字
    {
        {返回_FirstName; }
        组
        {
            _FirstName =价值;
            OnPropertyChanged(名字);
        }
    }    私人字符串_lastName;
    公共字符串姓氏
    {
        {返回_lastName; }
        组
        {
            _lastName =价值;
            OnPropertyChanged(姓氏);
        }
    }
    公共重写字符串的ToString()
    {
        返回的String.Format({0} {1},名字,姓氏);
    }    公共事件PropertyChangedEventHandler的PropertyChanged;    公共无效OnPropertyChanged(字符串propertyName的)
    {
        VAR处理器=的PropertyChanged;
        如果(!=处理空值)处理器(这一点,新PropertyChangedEventArgs(propertyName的));
    }
}

I've been trying to expand Josh Smith's demo MVVM application in order to better understand the principals behind it and I've hit a wall when trying to implement a filter function on a View using a ListView.

I have spent a few hours researching and dabbling but its just not working.

My first step was to bind a textbox in my view to a property in my ViewModel:

<TextBox Height="25" Name="txtFilter" Width="150" Text="{Binding Path=Filter, UpdateSourceTrigger=PropertyChanged}"/>

This matches in my VM:

public string Filter
    {
        get { return this.filter; }
        set
        {
            this.filter = value;
            OnFilterChanged();
        }
    }

My VM used a ObservableCollection for the datasource but I've tried to convert it into an ICollectionView after reading tutorials:

internal ObservableCollection<StaffViewModel> InnerStaff { get; set; }
    internal CollectionViewSource CvsStaff { get; set; }
    public ICollectionView AllStaff
    {
        get { return CvsStaff.View; }
    }

In my constructor I have specified:

CvsStaff = new CollectionViewSource();
CvsStaff.Source = this.InnerStaff;
CvsStaff.Filter += ApplyFilter;

When my Filter Property gets updated it calls OnFilterChanged which is:

private void OnFilterChanged()
    {
        CvsStaff.View.Refresh();
    }

My ApplyFilter Function is:

void ApplyFilter(object sender, FilterEventArgs e)
    {
        StaffViewModel svm = (StaffViewModel)e.Item;

        if (this.Filter.Length == 0)
        {
            e.Accepted = true;
        }
        else
        {
            e.Accepted = svm.LastName.Contains(Filter);
        }
    }

Is there a silly mistake that I've made that anyone can help me spot? I'm fairly new to WPF and the MVVM pattern so I'm still learning!

EDIT

In the View I bind the collection with:

<CollectionViewSource
  x:Key="StaffGroup"
  Source="{Binding Path=AllStaff}"
  />

and the ListView is as such:

<ListView
      Name="staffList"
      AlternationCount="2" 
      DataContext="{StaticResource StaffGroup}" 
      ItemContainerStyle="{StaticResource StaffItemStyle}"
      ItemsSource="{Binding}"
        Grid.Row="1">

解决方案

The binding is incorrect. You need to make a few changes. The first thing is to make sure that the DataContext is set correctly. Typically you'll do this on a parent of the ListView and not set it directly on the ListView control. This could be a UserControl / Window / etc.

So assuming you have a view model:

public class MainViewModel
{
    public MainViewModel()
    {
        //Create some fake data 
        InnerStaff = new ObservableCollection<StaffViewModel>();
        InnerStaff.Add(new StaffViewModel {FirstName = "Sue", LastName = "Bucknell"});
        InnerStaff.Add(new StaffViewModel {FirstName = "James", LastName = "Bucknell"});
        InnerStaff.Add(new StaffViewModel {FirstName = "John", LastName = "Harrod"});

        CvsStaff = new CollectionViewSource();
        CvsStaff.Source = this.InnerStaff;
        CvsStaff.Filter += ApplyFilter;
    }

    private string filter;

    public string Filter
    {
        get { return this.filter; }
        set
        {
            this.filter = value;
            OnFilterChanged();
        }
    }

    private void OnFilterChanged()
    {
        CvsStaff.View.Refresh();
    }

    internal ObservableCollection<StaffViewModel> InnerStaff { get; set; }
    internal CollectionViewSource CvsStaff { get; set; }
    public ICollectionView AllStaff
    {
        get { return CvsStaff.View; }
    }

    void ApplyFilter(object sender, FilterEventArgs e)
    {
        StaffViewModel svm = (StaffViewModel)e.Item;

        if (string.IsNullOrWhiteSpace(this.Filter) || this.Filter.Length == 0)
        {
            e.Accepted = true;
        }
        else
        {
            e.Accepted = svm.LastName.Contains(Filter);
        }
    }
}

And assuming you have a Window MainWindow.cs (code behind) you could (for this example) hook up the DataContext here.

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new MainViewModel();
    }
}

Then you have a few choices for doing your binding, you could specify your CollectionViewSource in XAML or in code, but you've done both. i.e. the xaml one, with the key x:key="StaffGroup" and the VM one CvsStaff. Let's say we get rid of the xaml one completely and use the VM one, which is setup correctly. Then you would bind using the ItemsSource property, like so:

<ListView Name="staffList" 
      AlternationCount="2" 
      ItemsSource="{Binding AllStaff}" 
      Grid.Row="1" />

Also small thing, I've changed the Filter to check for nulls and whitespace. You may also need to change it to be case-insensitive.

One other thing that I haven't mentioned here but is crucial is to implement INotifyPropertyChanged on your StaffViewModel - I assume you have, if not here's some code. You would typically also do this on most of your view models, to notify the view of changes to properties.

internal class StaffViewModel : INotifyPropertyChanged
{
    private string _firstName;
    public string FirstName
    {
        get { return _firstName; }
        set
        {
            _firstName = value;
            OnPropertyChanged("FirstName");
        }
    }

    private string _lastName;
    public string LastName
    {
        get { return _lastName; }
        set
        {
            _lastName = value;
            OnPropertyChanged("LastName");
        }
    }
    public override string ToString()
    {
        return string.Format("{0} {1}", FirstName, LastName);
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

这篇关于实现与约什 - 史密斯的WPF MVVM演示应用一个ListView过滤器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆