且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

数据绑定一个的ObservableCollection< T>在MVVM

更新时间:2022-10-30 17:07:05

INotifyPropertyChanged的需要在Movie类来实现,也避免了手动引发事件。 (现在你告诉认为,视图模型的名称属性改变,这不存在)


你的类可能看起来是这样的:

 公共类的电影:INotifyPropertyChanged的
{
    私人字符串_name =的String.Empty;
    公共字符串名称
    {
        {返回_name; }
        组
        {
            如果(_name!=值)
            {
                _name =价值;
                NotifyPropertyChanged(姓名);
            }
        }
    }

    //...All其它性能(以同样的方式)...

    公共事件PropertyChangedEventHandler的PropertyChanged;

    公共无效NotifyPropertyChanged(字符串propertyName的)
    {
        如果(的PropertyChanged!= NULL)
        {
            的PropertyChanged(这一点,新PropertyChangedEventArgs(propertyName的));
        }
    }
}
 

你的改变方法减少到:

 公共无效setMovieName(动画电影,串了newName)
    {
        Console.WriteLine(CurrentName:+ movie.Name);
        movie.Name =了newName; //通知现在的setter方法​​自动提升在电影类
        Console.WriteLine(新名称:+ movie.Name);
    }
 

I have a ListView with a Datatemplate that holds a list of Movies. It is databinded to a ObservableColection but whenever I edit the Movie.Name it does not update the ListView even though "Name" is called in my PropertyChangedEventHandler is called with "Name".

I add 2 "Movie"s to my collection in my initializer and these are shown correct (Klovn the Movie, Taken)

So when I click Edit it should change the text of the selected movie and change the Name of it to "Test" and is is changed but the change is not shown in the ListView but if I output Collection with a foreach then Name is 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");
        }
    }
}

The 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; }
    }
}

INotifyPropertyChanged needs to be Implemented in your Movie class, also avoid raising the event manually. (Right now you are telling the View that the ViewModel's property "Name" changed, which does not exist)


What your class might look like:

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));
        }
    }
}

What your changing method is reduced to:

    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);
    }