简体   繁体   中英

Accessing data from different ViewModels

I would like to access the data of different ViewModels in a single view. But the DataContext is a completely different one (MainViewModel in the MainView). Is it possible to set the respective ViewModel for each window control? Or is it better to create and reference the ObservableCollection<Student> Students only in the MainViewModel?

At the moment I would like to assign the property Students from the ViewModel StudentViewModel to this ComboBox.

MainViewModel (Setting the ApplicationViewModel as CurrentViewModel)

public class MainViewModel : ViewModelBase
    {
        public MainViewModel()
        {
            CurrentViewModel = ApplicationViewModel;            
            ShowStudentViewCommand = new RelayCommand(ShowStudentView);
        }


        public ViewModelBase CurrentViewModel
        {
            get => _currentViewModel;

            set
            {
                if (_currentViewModel == value) return;
                _currentViewModel = value;
                RaisePropertyChanged("CurrentViewModel");
            }
        }


        private ViewModelBase _currentViewModel;
        private static readonly ApplicationViewModel ApplicationViewModel = new ApplicationViewModel();
        private static readonly StudentViewModel StudentViewModel = new StudentViewModel();



        public ICommand ShowStudentViewCommand { get; }        
        public ICommand ShowApplicationViewCommand { get; }


        private void ShowStudentView()
        {
            CurrentViewModel = StudentViewModel;
        }


        private void ShowApplicationView()
        {
            CurrentViewModel = ApplicationViewModel;
        }     

    }

ApplicationViewModel and StudentViewModel (Loading data and creating the ObservableCollection)

public class ApplicationViewModel : ViewModelBase
    {
        public ApplicationViewModel()
        {

        }
    }


 public class StudentViewModel : ViewModelBase
 {
        private ObservableCollection<Student> _students;

        public StudentViewModel()
        {
            DataStudentService dataService = new DataStudentService();
            Students = new ObservableCollection<Student>(dataService.GetAllStudents());
        }

        public ObservableCollection<Student> Students
        {
            get => _students;

            private set
            {
                if (_students == value) return;
                _students = value;
                RaisePropertyChanged("Students");
            }
        }
    }

MainView.xaml (Sets the CurrentViewModel to display)

<Window x:Class="Test.View.MainView"
        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"
        mc:Ignorable="d"
        Title="Test" Height="750" Width="700" 

        DataContext="{Binding Main, Source={StaticResource Locator}}">

    <Grid>
        <ContentControl Grid.Row="1" Content="{Binding CurrentViewModel}" />
    </Grid>
</Window>

ApplicationView.xaml (This is currently displayed)

<UserControl x:Class="Test.View.ApplicationView"
             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:viewModel="clr-namespace:Test.ViewModel"
             mc:Ignorable="d">
<Grid >


    <ComboBox
        TextSearch.TextPath=""
        ItemsSource="{Binding Path=Students}"
        DisplayMemberPath="Name"
        SelectedValuePath="Name"
        SelectedValue="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
        SelectedItem="{Binding Path=SelectedStudent, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
        SelectedIndex="{Binding Path=SelectedStudentIndex, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
        IsSynchronizedWithCurrentItem="True"
        IsEditable="True"
        Width="200"
        Margin="0,0,20,0"
        VerticalContentAlignment="Center" />



    </Grid>
</UserControl>

The most straight-forward solution would be to stick to the MVVM pattern by creating a collection and filling it with the data from the other class as you already mentioned. It's easy and everyone knows what's going on. Also, That way the context of the data stays in the same viewmodel and - if you change something - it also stays in that context. In your case that means you have to create a ObservableCollection<Student> Students and fill its content in the MainViewModel .


If that data has to be accessed from all over your application you should think about implementing a DataManager (a singleton, for example) rather than copying the data in every viewmodel.

Found a solution:

MainViewModel

public class MainViewModel : ViewModelBase
{
    public StudentViewModel StudentViewModel { get; set; }

    public MainViewModel()
    {
        StudentViewModel = new StudentViewModel();
    }
}

MainView

<ComboBox
DataContext="{Binding StudentViewModel}"
ItemsSource="{Binding Path=Students, UpdateSourceTrigger=PropertyChanged}"
/>

StudentViewModel

private ObservableCollection<Student> _students;

public ObservableCollection<Student> Students
    {
        get => _students;
        set
            {
                if (_students == value) return;
                _students = value;
                RaisePropertyChanged("Students");
            }
        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM