MVVM Light – 用户控件作为视图

我决定使用MVVM Light库来帮助设计UI。 经过大量的研究和反复试验,我还没有找到我想要的答案。 我用谷歌搜索并阅读了我能找到的每个StackOverflow问题,然而,我的问题似乎在SO上是独一无二的。

我希望设计一个带有单个窗口的UI,并使用不同的Views / UserControls填充它。 我不想在UserControls中使用共享导航栏,也不想弹出多个窗口。 每个View / UserControl都应绑定到自己的ViewModel,而MainWindow将绑定到MainViewModel。

示例场景 – 具有3个UserControl的MainWindow

1. MainWindow populates with first UserControl which has a listbox and 3 buttons, the first button is enabled. 2. User clicks the first button. 3. MainWindow populates with second UserControl. 

或者,另外

  2. User selects choice from a listbox, button two and three become available. 3. User clicks second/third button. 4. MainWindow populates with second/third UserControl. 

等等

也许我的方法不现实,但我觉得这必须是可能的。 我不明白如何让所有这些作品在概念上发挥作用。 我的欲望绝不是独一无二的。 如果您认为这是重复的问题,请重定向。 干杯。


为了使事情更容易理解,我在下面列出了一些课程。 首先,我的App.xaml。

               

MainWindow.xaml

     

ViewModelLocator.cs

 namespace Bobcat_BETA.ViewModels { public class ViewModelLocator { private static MainViewModel _main; public ViewModelLocator() { _main = new MainViewModel(); } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "This non-static member is needed for data binding purposes.")] public MainViewModel Main { get { return _main; } } } } 

MainViewModel.cs

 namespace Bobcat_BETA.ViewModels { public class MainViewModel : ViewModelBase { private ViewModelBase _currentViewModel; readonly static SavedScenariosViewModel _savedScenarioViewModel = new SavedScenariosViewModel(); readonly static ScenarioEditorViewModel _scenarioEditorViewModel = new ScenarioEditorViewModel(); readonly static SimulatorViewModel _simulatorViewModel = new SimulatorViewModel(); public ViewModelBase CurrentViewModel { get { return _currentViewModel; } set { if (_currentViewModel == value) return; _currentViewModel = value; RaisePropertyChanged("CurrentViewModel"); } } public MainViewModel() { CurrentViewModel = MainViewModel._savedScenarioViewModel; SavedScenarioViewCommand = new RelayCommand(() => ExecuteSavedScenarioViewCommand()); ScenarioEditorViewCommand = new RelayCommand(() => ExecuteScenarioEidtorViewCommand()); SimulatorViewCommand = new RelayCommand(() => ExecuteSimulatorViewCommand()); } public ICommand SavedScenarioViewCommand { get; private set; } public ICommand ScenarioEditorViewCommand { get; private set; } public ICommand SimulatorViewCommand { get; private set; } private void ExecuteSavedScenarioViewCommand() { CurrentViewModel = MainViewModel._savedScenarioViewModel; } private void ExecuteScenarioEidtorViewCommand() { CurrentViewModel = MainViewModel._scenarioEditorViewModel; } private void ExecuteSimulatorViewCommand() { CurrentViewModel = MainViewModel._simulatorViewModel; } } } 

SavedScenariosViewModel.cs

 namespace Bobcat_BETA.ViewModels { public class SavedScenariosViewModel : ViewModelBase { public SavedScenariosViewModel() { } ObservableCollection _scenarioModels = new ObservableCollection() { new ScenarioModel() {Name = "Scenario 0", ID = 000, Desc = "This will describe the Scenario Model."}, new ScenarioModel() {Name = "Scenario 1", ID = 001, Desc = "This will describe the Scenario Model."}, new ScenarioModel() {Name = "Scenario 2", ID = 002, Desc = "This will describe the Scenario Model."}, new ScenarioModel() {Name = "Scenario 3", ID = 003, Desc = "This will describe the Scenario Model."}, new ScenarioModel() {Name = "Scenario 4", ID = 004, Desc = "This will describe the Scenario Model."}, new ScenarioModel() {Name = "Scenario 5", ID = 005, Desc = "This will describe the Scenario Model."}, new ScenarioModel() {Name = "Scenario 6", ID = 006, Desc = "This will describe the Scenario Model."}, new ScenarioModel() {Name = "Scenario 7", ID = 007, Desc = "This will describe the Scenario Model."}, new ScenarioModel() {Name = "Scenario 8", ID = 008, Desc = "This will describe the Scenario Model."}, new ScenarioModel() {Name = "Scenario 9", ID = 009, Desc = "This will describe the Scenario Model."} }; public ObservableCollection ScenarioModels { get { return _scenarioModels; } } } } 

SavedScenariosUserControl.xaml

             

如果有什么不清楚,我也可以添加模型类,但我假设你可以从正在发生的事情做出推断。 谢谢。

所以你的方法非常合理。 您必须使用某些复杂的function才能获得该function。 我不得不使用包含所有视图模型的“MainViewModel”。 这些视图模型的行为使得当数据上下文切换到不同的视图模型时,相应的用户控件将更改为适当的视图。 Sheridan 在这里回答了我遵循的一个很好的例子。 使用适当的数据模板连接到app.xaml,数据上下文切换将像魔术一样处理:D

我从Sheridan的例子中分离出来(因为我不想创建一个单独的中继命令类/对象),我实际上使用mvvm light(galasoft)从我的视图模型发送消息,然后将消息发送回“MainViewModel”以切换其数据上下文。 可以在此处找到使用MVVM光消息的一个很好的示例。 从“子”视图模型发送消息并将其注册在“MainViewModel”中。

祝好运!

难道你不能使用接口作为例如IChildLayout吗? 每个ViewModel都inheritance了这个接口……

 public interface IChildLayout:INotifyPropertyChanged { public MainWindows_ViewModel Parent; } 

在你的MainWindows ViewModel中你可以有这样的东西……

属性IChildLayout,当您单击按钮时会更改…

 public class MainWindows_ViewModel:INotifyPropertyChanged { public MainWindows_ViewModel() { //Here i set the default ViewModel this.Child=new First_ViewModel(){Parent=this}; } private IChildLayout _child; public IChildLayout Child { get { return _child; } set { _child=value; _child.Parent=this; NotifyPropertyChanged("Child"); } } #region INotifyPropertyChangedMembers... } 

对于每个布局,您可以检索父窗口ViewModel(通过从它自己的ViewModel编辑“Child”属性来切换布局非常重要…)

您将一个UserControl放在主窗口(在xaml中),内容被绑定到您的Child属性,然后每次更改您的Child属性时都会刷新。

                

在这种情况下,您的First_ViewModel可以是:(在此示例中,我使用prism DelegateCommand绑定按钮操作…

 public class First_ViewModel:IChildLayout { public MainWindows_ViewModel Parent {get;set;} public ICommand cmdBtn1click{get;set;} private Pass_to_second_ViewModel() { //Here i change the Parent Child Property, it will switch to Second_View.xaml... this.Parent.Child=new Second_ViewModel(); } public First_ViewModel() { // Here i connect the button to the command with Prism... this.cmdBtn1click=new DelegateCommand(()=>Pass_to_second_ViewModel()); } #region INotifyPropertyChangedMembers... 

}

我希望这对你有所帮助,我做了这样的事情来管理WPF应用程序中的不同Tab。