How can I "bin" an ObservableCollection to several views and keep it synchronized between them? WPF

1

I need to bind a ObservableCollection to several views and that this list stays synchronized among all the views, in case of modifying the list (adding, removing or updating a value in said list) the change is replicated for all the views .

    
asked by Braster 17.11.2016 в 16:27
source

4 answers

1

If when you say 'other views' you mean windows or elements that are not in the same form, then what you can do is that when you create the list, you send the observable list to the constructor at each view and bind the list their respective elements in each view.

ObservableCollection<string> nombres = new ObservableCollection<string>();
Vista1 vista1 = new Vista1(nombres);
Vista2 vista2 = new Vista2(nombres);
Vista3 vista3 = new Vista3(nombres);

And in the views:

public partial class Vista1
{
  public Vista1(ObservableCollection<string> nombres)
  {
    InitializeComponents();
    NombresListView.ItemsSource = nombres;

  }
}

And you repeat the same for the other views.

What would be happening is that as you send the same reference list to each view, adding an item to the list would execute the event CollectionChanged in each instance of the views.

    
answered by 20.04.2017 в 05:01
0

As far as I can understand, what you need is simple:

1.- Your model must implement INotifyPropertyChanged:

using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace MvvmLight4.Model
{
    public class MiClase : INotifyPropertyChanged
    {


        private string _property1;

        public string Property1
        {
            get { return _property1; }
            set { _property1 = value; OnPropertyChanged(); }
        }

        private string _property2;

        public string Property2
        {
            get { return _property2; }
            set { _property2 = value; OnPropertyChanged(); }
        }


        public static IEnumerable<MiClase> GenerarObjetos()
        {
            return new List<MiClase>()
            {
                new MiClase { Property1 = "1-P1", Property2 = "1-P2"  },
                new MiClase { Property1 = "2-P1", Property2 = "2-P2"  }
            };
        }


        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

2.- Create an ObsrevableCollection property in the ViewModel:

using GalaSoft.MvvmLight;
using MvvmLight4.Model;
using System.Collections.ObjectModel;

namespace MvvmLight4.ViewModel
{

    public class MainViewModel : ViewModelBase
    {


        public MainViewModel(IDataService dataService)
        {
            Datos = new ObservableCollection<MiClase>(MiClase.GenerarObjetos());
        }



        private ObservableCollection<MiClase> _datos;

        public ObservableCollection<MiClase> Datos
        {
            get { return _datos; }
            set { _datos = value; RaisePropertyChanged(nameof(Datos)); }
        }

    }
}

3.- Link in your view to the controls that you want:

                                                        

    <TextBlock FontSize="36"
               FontWeight="Bold"
               Foreground="Purple"
               Text="{Binding WelcomeTitle}"
               VerticalAlignment="Center"
               HorizontalAlignment="Center"
               TextWrapping="Wrap" Margin="362,94,361,82" Grid.Row="1" />
    <DataGrid Grid.Row="0" AutoGenerateColumns="True" ItemsSource="{Binding Datos}" />
    <DataGrid Grid.Row="1" AutoGenerateColumns="True" ItemsSource="{Binding Datos}" />
    <DataGrid Grid.Row="2" AutoGenerateColumns="True" ItemsSource="{Binding Datos}" />
</Grid>

And running smoothly.

    
answered by 18.11.2016 в 08:59
0

If it works, I'll tell you how I did it:

First of all I created a singleton class with an ObservableCollection:

public class Singleton : INotifyPropertyChanged
{
    private static Singleton instance = null;


    private ObservableCollection<MiClase> _lista = new ObservableCollection<MiClase>();

    public ObservableCollection<MiClase> Lista
    {
        get { return _lista; }
        set { _lista = value; OnPropertyChanged(); }
    }



    private Singleton()
    {
    }

    public static Singleton Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new Singleton();
            }
            return instance;
        }
    }



    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

And then I created 2 ViewModel, with an equal ObservableCollection property, but modifying its Get, like this:

public class ViewModel1 : INotifyPropertyChanged
{


    private ObservableCollection<MiClase> _listaPantalla1;

    public ObservableCollection<MiClase> ListaPantalla1
    {
        get
        {
            return Singleton.Instance.Lista;
        }
        set { _listaPantalla1 = value; OnPropertyChanged(); }
    }


    public ViewModel1()
    {
        ListaPantalla1.Add(new MiClase { Property1 = "Uno Pantalla1", Property2 = "Uno Pantalla1" });
    }



    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

}

public class ViewModel2 : INotifyPropertyChanged
{

    private ObservableCollection<MiClase> _listaPantalla2;

    public ObservableCollection<MiClase> ListaPantalla2
    {
        get
        {
            return Singleton.Instance.Lista;
        }
        set { _listaPantalla2 = value; OnPropertyChanged(); }
    }


    public ViewModel2()
    {
        ListaPantalla2.Add(new MiClase { Property1 = "Uno Pantalla2", Property2 = "Uno Pantalla2" });
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

Then I have linked the views with their ViewModels and I have added a DataGrid to each one and I have linked their ItemSource to the list properties of their respective ViewModels, and it works, if I modify something in one it is reflected in the other and vice versa.

If you need the code, tell me and I'll give you a download link.

I hope it helps you.

    
answered by 23.11.2016 в 22:22
0

You can place the list in a ViewModel and the ViewModel in the App.xaml

<Application.Resources>
    <ResourceDictionary>                        
        <!-- ViewModels -->
        <vm:MyViewModel                   x:Key="MyVM" />
    </ResourceDictionary> 
</Application.Resources>

With that you have the centralized collection and since the App.xaml is above all the other classes you do not need more than to call it, you can define it in your classes as property

private ObservableCollection<MiClase> _myVM;

public ObservableCollection<MiClase> MyVM
        {
            get { return _myVM; }
            set { _myVM= value; }
}

And then call it directly in the constructor of each class where you need to use it or assign it as ItemSource or DataContext where you want to visualize it:

MyVM = (ObservableCollection<MiClas>)FindResource("MyVM");

I hope you have served, greetings.

    
answered by 06.12.2016 в 20:55