在MVVM中数据绑定ObservableCollection <t> </t>

时间:2011-01-21 18:55:12

标签: c# .net wpf xaml data-binding

我有一个带有Datatemplate的ListView,其中包含一个电影列表。它被数据绑定到一个ObservableColection,但每当我编辑Movie.Name时它都不会更新ListView,即使在我的PropertyChangedEventHandler中调用了“Name”并使用“Name”调用它。

我在我的初始化程序中将2个“电影”添加到我的收藏中,这些都显示正确(Klovn the Movie,Taken)

因此,当我单击编辑时,它应该更改所选电影的文本并将其名称更改为“测试”并且 已更改,但更改未显示在ListView中但是如果我使用foreach输出集合,然后命名为Test。

View.xaml

<Window x:Class="MovieDB3.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <DockPanel>
        <Menu DockPanel.Dock="Top">
            <MenuItem Header="File">
                <MenuItem Header="Edit" Click="MenuEditClick"/>
            </MenuItem>
        </Menu>
        <Grid DockPanel.Dock="Top">
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <ListView VerticalAlignment="Stretch" Name="ListViewMovies" ItemsSource="{Binding Path=Collection}" IsSynchronizedWithCurrentItem="True" >
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <WrapPanel>
                            <TextBlock Text="{Binding Path=Name}"/>
                        </WrapPanel>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </Grid>
    </DockPanel>
</Window>

View.cs

using System;
using System.Windows;
using MovieDB3.Models;
using MovieDB3.ViewModels;

namespace MovieDB3
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private MainViewModel MVM;
        public MainWindow()
        {
            InitializeComponent();
            MVM = new MainViewModel();
            DataContext = MVM;
        }

        private void MenuEditClick(object sender, RoutedEventArgs e)
        {
            MVM.setMovieName((Movie)ListViewMovies.SelectedItem, "test");
        }
    }
}

ViewModel

using System;
using System.ComponentModel;
using MovieDB3.Models;
using System.Collections.ObjectModel;

namespace MovieDB3.ViewModels
{
    class MainViewModel : INotifyPropertyChanged
    {
        public ObservableCollection<Movie> Collection {get; set;}

        public MainViewModel()
        {
            Collection = new ObservableCollection<Movie>();

            //Test kode
            Movie movie = new Movie();
            movie.Name = "Klovn The Movie";
            Collection.Add(movie);
            movie = new Movie();
            movie.Name = "Taken";
            Collection.Add(movie);
        }

        public void setMovieName(Movie movie, string newName)
        {
            //movie.Name = newName;
            Console.WriteLine("CurrentName: " + movie.Name);
            int i = Collection.IndexOf(movie);
            Collection[i].Name = newName;
            Console.WriteLine("NewName: " + movie.Name);
            NotifyPropertyChanged("Name");
        }

        public void setMovieName(string currentName, string newName)
        {
            foreach (Movie movie in Collection)
            {
                if (movie.Name.Equals(currentName))
                {
                    movie.Name = newName;
                    NotifyPropertyChanged("Name");
                    return;
                }
            }
        }

        //public string MovieName
        //{
        //    set 
        //    {

        //        NotifyPropertyChanged("MovieName");
        //    }
        //}

        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }
    }
}

Movie.cs

using System;

namespace MovieDB3.Models
{
    class Movie
    {
        public string Name { get; set; }
        public int Id { get; set; }
        public double Rating { get; set; }
        public DateTime Release { get; set; }
        public TimeSpan Runtime { get; set; }
        public String Trailer { get; set; }
    }
}

4 个答案:

答案 0 :(得分:8)

INotifyPropertyChanged需要在您的Movie类中实现,也避免手动引发事件。 (现在您告诉View ViewModel的属性“Name”已更改,但不存在)


你的课程可能是什么样的:

public class Movie : INotifyPropertyChanged
{
    private string _name = String.Empty;
    public string Name
    {
        get { return _name; }
        set
        {
            if (_name != value)
            {
                _name = value;
                NotifyPropertyChanged("Name");
            }
        }
    }

    //...All the other properties (the same way)...

    public event PropertyChangedEventHandler PropertyChanged;

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

您的更改方法简化为:

    public void setMovieName(Movie movie, string newName)
    {
        Console.WriteLine("CurrentName: " + movie.Name);
        movie.Name = newName; //The notification is now raised automatically in the setter of the property in the movie class
        Console.WriteLine("NewName: " + movie.Name);
    }

答案 1 :(得分:2)

我认为电影本身需要实现INotifyPropertyChanged。您正在通过错误的对象(viewmodel)进行通知。

答案 2 :(得分:2)

您还需要在Movie类上实现INotifyPropertyChanged。

您在setMovieName方法中发送的通知实际上并不意味着什么 - 它只是一个“属性”名称。它也可以是“Foo”,你的事件处理程序会说“Foo”。

相反,您需要更新Movie对象本身。

最好的实现可能是你创建一个通知INotifyPropertyChanged的抽象类,然后从中派生你的ViewModel和你的Movie类,因为两者都应该实现它。

您将从ViewModel绑定属性,并且您还将在该ViewModel中绑定可观察对象(即Movie)。

答案 3 :(得分:0)

目前,您MainViewModel举起NotifyPropertyChanged事件,Name更改Movie。相反,您的Movie实例应该引发这些事件,因为您的{{1}}对象是该属性绑定的对象。

相关问题