Search code examples
c#.netwpfxamlmvvm

Inserting new item on ObservableCollection doesn't reflect on view, used DependencyProperty


My MainWindow.xml

<Window x:Class="WpfApp5.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp5"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext>
        <local:vm/>
    </Window.DataContext>
    <StackPanel>
        <Button Content="Click" Command="{Binding addCommand}"/>
        <local:ModifiedControlView Items="{Binding People}" />
    </StackPanel>
</Window>

My MainViewModel

public partial class vm : ObservableObject
    {
        public class Person
        {
            public string Name { get; set; }
            public int Age { get; set; }
        }
        public ObservableCollection<Person> People { get; set; } = new ObservableCollection<Person>();

        public vm()
        {
        }

        [RelayCommand]
        private void add()
        {
            People.Add(new Person { Name = "New", Age = 0 });
        }
    }

ModifiedControlView.xaml

<UserControl x:Class="WpfApp5.ModifiedControlView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WpfApp5"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <ListView ItemsSource="{Binding}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Name}"/>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</UserControl>

ModifiedControlView.xaml.c

public partial class ModifiedControlView : UserControl
    {
        public ModifiedControlView()
        {
            InitializeComponent();
        }

        public static readonly DependencyProperty ItemsProperty =
            DependencyProperty.Register("Items", typeof(ObservableCollection<Person>), typeof(ModifiedControlView), new PropertyMetadata(null));

        public ObservableCollection<Person> Items
        {
            get { return (ObservableCollection<Person>)GetValue(ItemsProperty); }
            set { SetValue(ItemsProperty, value); }
        }
    }

Why inserting new item on People Collection in VM, doesn't reflect in the view?

If I don't use the dependency property it works, but I need to use this collection inside a usercontrol with dependency property.


Solution

  • You want to bind the ItemsSource of the ListView in the UserControl's XAML to the Items property of the UserControl:

    <ListView ItemsSource="{Binding Items,
                            RelativeSource={RelativeSource AncestorType=UserControl}}">
    

    As a note, it is not necessary to declare the Items property as an ObservableCollection<Person>.

    It would provide greater flexibilty to use IEnumerable<Person> as property type. With an ObservableCollection<Person> as the source property type in the view model, notification events about collection changed would still be propagated to the control.