WPF ListView MVVM绑定不会更新UI

时间:2016-08-11 07:10:54

标签: .net wpf listview mvvm data-binding

这是我的代码:

型号:

public class Person
{
    public string FirstName { get; set; }
}

ViewModelBase:

public abstract class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

视图模型:

public sealed class PeopleViewModel : ViewModelBase
{
    private ICollectionView _collectionView;
    public ICollectionView View => _collectionView;

    private ObservableCollection<Person> _personCollection;
    public ObservableCollection<Person> PersonCollection
    {
        get { return _personCollection; }
        set
        {
            if (value != this._personCollection)
                _personCollection = value;
            OnPropertyChanged("PersonCollection");
        }
    }

    private string _filterSearchText;


    public PeopleViewModel()
    {
        _personCollection = new ObservableCollection<Person>();
        _collectionView = CollectionViewSource.GetDefaultView(PersonCollection);

        Add(new Person() {FirstName="Homer"});
        Add(new Person() {FirstName="Bart"});
        Add(new Person() {FirstName="Lisa"});

    }

    public void Add(Person person)
    {
        PersonCollection.Insert(0, person);
    }

    public string FilterSearchText
    {
        get { return _filterSearchText; }
        set
        {
            _filterSearchText = value;
            OnPropertyChanged("FilterSearchText");

            if (string.IsNullOrEmpty(value))
            {
                _collectionView.Filter = null;
            }
            else
            {
                _collectionView.Filter = x => 
                ((Person)x).FirstName.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0;
            }
        }
    }
}

MainWindow.xaml.cs:

public partial class MainWindow : Window
{
    private readonly PeopleViewModel _peopleViewModel = new PeopleViewModel();

    public MainWindow()
    {
        InitializeComponent();

        this.DataContext = _peopleViewModel;
    }

    private void MyUpdateLogic()
    {
        var person = new Person() {FirstName="Marge"} 
        _peopleViewModel.Add(person);
    }
    ...
}

MainWindow.xaml

<Grid>
    <Grid DataContext="{Binding Source={StaticResource PeopleViewModel}}">
        <Grid.RowDefinitions>
            <RowDefinition MinHeight="243" />
        </Grid.RowDefinitions>
        <ListView x:Name="personListView"
              ItemsSource="{Binding PersonCollection}"
              Grid.Row="0"
              Margin="0,0,0,5" >
            <ListView.View>
                <GridView ColumnHeaderContainerStyle="{StaticResource CustomHeaderStyle}">
                    <GridViewColumn Width="Auto" DisplayMemberBinding="{Binding FirstName}"/>
                </GridView>
            </ListView.View>
            <ListView.ItemContainerStyle>
                <Style TargetType="ListViewItem">
                    <Setter Property="Height" Value="20" />
                    <EventSetter Event="MouseDoubleClick"  
                             Handler="MyUpdateLogic" />
                </Style>
            </ListView.ItemContainerStyle>
        </ListView>
        <TextBox x:Name="searchTextBox" 
             Text="{Binding FilterSearchText, UpdateSourceTrigger=PropertyChanged}"
             TextWrapping="Wrap"
             MaxHeight="25" 
             MinHeight="25" 
             Height="25"
             Grid.Row="1" 
             VerticalAlignment="Bottom" />
    </Grid>
</Grid>

它在UI(Homer,Bart,Lisa)上显示初始列表的最有趣的部分,甚至过滤效果很好,当我更新searchTextBox时,它更新UI并仅显示列表视图中的相应元素。但是当我添加新元素时,它并没有更新UI,即使它确实为可观察集合PersonCollection添加了新元素。

我在这里缺少什么?如果我错误地实现了MVVM模式,也请告诉我。

更新

我还尝试绑定到ICollectionView:<ListView x:Name="personListView" ItemsSource="{Binding View}",它没有用。

尝试订阅PeopleViewModel构造函数中的Refresh:

_personCollection.OnChange += _collectionView.Refresh();

在向列表中添加新元素后立即添加刷新:

public void Add(Person person)
{
    PersonCollection.Insert(0, person);
    _collectionView.Refresh();
}

它也没有用。

1 个答案:

答案 0 :(得分:3)

您将Grid的datacontext设置两次,只需删除此绑定

DataContext="{Binding Source={StaticResource PeopleViewModel}}"

在MainWindow构造函数中添加此行,

this.DataContext = _peopleViewModel;

您将整个DataContext设置为绑定到此实例,您应该知道Datacontext是否从父控件继承,如果您没有覆盖它。