从不同的ViewModel访问数据

时间:2019-02-22 11:38:16

标签: c# wpf mvvm viewmodel mvvm-light

我想在一个视图中访问不同ViewModel的数据。 但是DataContext是一个完全不同的对象(MainView中的MainViewModel)。是否可以为每个窗口控件设置各自的ViewModel? 还是仅在MainViewModel中创建和引用ObservableCollection<Student> Students更好?

此刻,我想将ViewModel Students中的属性StudentViewModel分配给此ComboBox。

MainViewModel (将ApplicationViewModel设置为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和StudentViewModel (加载数据并创建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 (设置要显示的CurrentViewModel)

<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 (当前显示)

<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>

2 个答案:

答案 0 :(得分:1)

最直接的解决方案是坚持创建MVVM模式,方法是创建一个集合,并用您已经提到的其他类的数据填充它。这很容易,每个人都知道发生了什么。此外,这样,数据的 context 会保留在相同的视图模型中,并且-如果您更改某些内容,它也会保留在该上下文中。就您而言,这意味着您必须创建一个<Button> <Button.Resources> <SolidColorBrush x:Key="MyBrush" Color="#FFD71526"/> </Button.Resources> <Button.Background> <StaticResource ResourceKey="MyBrush" /> </Button.Background> </Button> 并将其内容填充到<?xml version="1.0" encoding="UTF-8"?> <configuration> <system.webServer> <security> <authorization> <add accessType="Allow" users="?" /> </authorization> </security> <httpRedirect enabled="false" /> <rewrite> <rules> <rule name="ReverseProxyInboundRule1" stopProcessing="true"> <match url="(.*)" /> <action type="Rewrite" url="http://localhost:8080/{R:1}" /> </rule> </rules> <outboundRules> <rule name="outbound"> <match filterByTags="Link, Script" pattern="(.*)" /> <action type="Rewrite" value="http://[mydomain.xyz]{R:1}" /> </rule> </outboundRules> </rewrite> </system.webServer> </configuration> 中。


如果必须从整个应用程序访问该数据,则应考虑实现DataManager(例如单例),而不是在每个视图模型中复制数据。

答案 1 :(得分:0)

找到了解决方案:

MainViewModel

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Checking for first time launch - before calling setContentView()
        prefManager = new PrefManager(this);
        if (!prefManager.isFirstTimeLaunch()) {
            launchHomeScreen();
            finish();
        }

        // Making notification bar transparent
        if (Build.VERSION.SDK_INT >= 21) {
            getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
        }

        setContentView(R.layout.activity_welcome);

        viewPager = (ViewPager) findViewById(R.id.view_pager);
        dotsLayout = (LinearLayout) findViewById(R.id.layoutDots);
        btnSkip = (Button) findViewById(R.id.btn_skip);
        btnNext = (Button) findViewById(R.id.btn_next);


        // layouts of all welcome sliders
        // add few more layouts if you want
        layouts = new int[]{
                R.layout.welcome_slide1,
                R.layout.welcome_slide2,
                R.layout.welcome_slide3,
                R.layout.welcome_slide4};

        // adding bottom dots
        addBottomDots(0);

        // making notification bar transparent
        changeStatusBarColor();

        myViewPagerAdapter = new MyViewPagerAdapter();
        viewPager.setAdapter(myViewPagerAdapter);
        viewPager.addOnPageChangeListener(viewPagerPageChangeListener);

        btnSkip.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                launchHomeScreen();
            }
        });

MainView

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

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

StudentViewModel

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