C# MVVM Light-用户控件作为视图

C# MVVM Light-用户控件作为视图,c#,xaml,mvvm,user-controls,mvvm-light,C#,Xaml,Mvvm,User Controls,Mvvm Light,我决定使用MVVM Light库来帮助设计UI。经过大量的研究和反复试验,我还没有找到我正在寻找的答案。我已经在谷歌上搜索并阅读了我能找到的每个StackOverflow问题,然而,我的问题似乎是独一无二的 我希望设计一个只有一个窗口的UI,并用不同的视图/用户控件填充它。我不希望用户控件之间共享导航栏,也不希望弹出多个窗口。每个视图/用户控件都应绑定到自己的ViewModel,而MainWindow将绑定到MainViewModel 示例场景-具有3个用户控件的主窗口 1. MainWindo

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

我希望设计一个只有一个窗口的UI,并用不同的视图/用户控件填充它。我不希望用户控件之间共享导航栏,也不希望弹出多个窗口。每个视图/用户控件都应绑定到自己的ViewModel,而MainWindow将绑定到MainViewModel

示例场景-具有3个用户控件的主窗口

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

<Application x:Class="Bobcat_BETA.App"
             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:views="clr-namespace:Bobcat_BETA.UserControls"
             xmlns:vm="clr-namespace:Bobcat_BETA.ViewModels"
             StartupUri="MainWindow.xaml"
             mc:Ignorable="d">
    <Application.Resources>
        <vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" />

        <DataTemplate DataType="{x:Type vm:SavedScenariosViewModel}">
            <views:SavedScenariosUserControl />
        </DataTemplate>
        <DataTemplate DataType="{x:Type vm:ScenarioEditorViewModel}">
            <views:ScenarioEditorUserControl />
        </DataTemplate>
        <DataTemplate DataType="{x:Type vm:SimulatorViewModel}">
            <views:SimulatorUserControl />
        </DataTemplate>

    </Application.Resources>
</Application>
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;
        }
    }
}
namespace Bobcat_BETA.ViewModels
{
    public class SavedScenariosViewModel : ViewModelBase
    {

        public SavedScenariosViewModel()
        {
        }

        ObservableCollection<ScenarioModel> _scenarioModels = new ObservableCollection<ScenarioModel>()
        {
            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<ScenarioModel> ScenarioModels
        {
            get { return _scenarioModels; }
        }

    }
}
SavedScenariosViewModel.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;
        }
    }
}
namespace Bobcat_BETA.ViewModels
{
    public class SavedScenariosViewModel : ViewModelBase
    {

        public SavedScenariosViewModel()
        {
        }

        ObservableCollection<ScenarioModel> _scenarioModels = new ObservableCollection<ScenarioModel>()
        {
            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<ScenarioModel> ScenarioModels
        {
            get { return _scenarioModels; }
        }

    }
}
名称空间山猫_BETA.ViewModels
{
公共类SavedScenariosViewModel:ViewModelBase
{
公共存储的scenariosviewmodel()
{
}
ObservableCollection\u scenarioModels=新的ObservableCollection()
{
new ScenarioModel(){Name=“Scenario 0”,ID=000,Desc=“这将描述场景模型。”},
new ScenarioModel(){Name=“Scenario 1”,ID=001,Desc=“这将描述场景模型。”},
new ScenarioModel(){Name=“Scenario 2”,ID=002,Desc=“这将描述场景模型。”},
new ScenarioModel(){Name=“Scenario 3”,ID=003,Desc=“这将描述场景模型。”},
new ScenarioModel(){Name=“Scenario 4”,ID=004,Desc=“这将描述场景模型。”},
new ScenarioModel(){Name=“Scenario 5”,ID=005,Desc=“这将描述场景模型。”},
new ScenarioModel(){Name=“Scenario 6”,ID=006,Desc=“这将描述场景模型。”},
new ScenarioModel(){Name=“Scenario 7”,ID=007,Desc=“这将描述场景模型。”},
new ScenarioModel(){Name=“Scenario 8”,ID=008,Desc=“这将描述场景模型。”},
new ScenarioModel(){Name=“Scenario 9”,ID=009,Desc=“这将描述场景模型。”}
};
公共可观测收集场景模型
{
获取{return\u scenarioModels;}
}
}
}
SavedScenariosUserControl.xaml

<UserControl x:Class="Bobcat_BETA.UserControls.SavedScenariosUserControl"
             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:vm="clr-namespace:Bobcat_BETA.ViewModels"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">

    <UserControl.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/Dictionaries/MasterDictionary.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </UserControl.Resources>

    <UserControl.Style>
        <DynamicResource ResourceKey="GeneralUserControl"/>
    </UserControl.Style>

    <Grid>
        <Label Content="Saved Scenario Selection" 
                Style="{StaticResource GeneralLabel}" HorizontalAlignment="Left" Margin="26,30,0,0" VerticalAlignment="Top" Height="62" Width="345"/>
        <Label Content="Chose Flight Model:" 
                Style="{StaticResource GeneralLabel2}"
                HorizontalAlignment="Left" Margin="27,111,0,0" VerticalAlignment="Top" Height="43" Width="345"/>
        <ListBox Style="{StaticResource GeneralListBox}"
                HorizontalAlignment="Left" Height="509" Margin="27,154,0,0" VerticalAlignment="Top" Width="345"
                ItemsSource="{Binding ScenarioModels}"/>

        <Button Content="New" 
                Style="{StaticResource TransitionButton}"
                HorizontalAlignment="Left" Margin="948,601,0,0" VerticalAlignment="Top" MinHeight="62" MinWidth="150" IsEnabled="True"
                Command="{Binding ScenarioEditorViewCommand}"/>

        <Button Content="Edit"
                Style="{StaticResource TransitionButton}"
                HorizontalAlignment="Left" Margin="401,519,0,0" VerticalAlignment="Top" MinHeight="62" MinWidth="150"
                Command="{Binding SaveScenariosViewCommand}"/>
        <Button Content="Load"
                Style="{StaticResource TransitionButton}"
                HorizontalAlignment="Left" Margin="401,601,0,0" VerticalAlignment="Top" MinHeight="62" MinWidth="150"
                Command="{Binding SimulatorViewCommand}"/>

    </Grid>
</UserControl>


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

您不能使用界面作为示例IChildLayout吗? 每个ViewModel继承此界面的

public interface IChildLayout:INotifyPropertyChanged
{
    public MainWindows_ViewModel Parent;
}
在您的主Windows ViewModel中,您可以有如下内容

属性布局,当您单击按钮时会发生更改

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编辑“子”属性来切换布局非常重要…)

在主窗口(在xaml中)中放置一个UserControl,内容绑定到子属性,然后每次更改子属性时都会刷新该内容

<Windows>
    <Windows.DataContext>
        <local:MainWindows_ViewModel/>
    </Windows.DataContext>
    <UserControl Content={Binding Child}>
        <UserControl.Resources>
            <DataTemplate DataType="{x:Type ViewModels:First_ViewModel}">
                    <Controls:First_View DataContext="{Binding}"/>
            </DataTemplate>
            <DataTemplate DataType="{x:Type ViewModels:Second_ViewModel}">
                    <Controls:Second_View DataContext="{Binding}" />
            </DataTemplate>
         </UserControl.Resources>
    </UserControl>
</Windows>
}


我希望这将对您有所帮助,我这样做是为了管理WPF应用程序中的不同选项卡。

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

我与Sheridan的示例不同(因为我不想创建单独的中继命令类/对象),实际上我使用mvvm light(galasoft)将消息从我的viewmodels发送到消息回“MainViewModel”,以切换其数据上下文。可以找到一个使用MVVM轻消息传递的好例子。从“子”视图模型发送消息,并将其注册到“MainViewModel”


祝你好运

这看起来合乎逻辑,所以我会尽我最大的努力让它工作。欢迎提供任何其他代码示例。谢谢。实际上,我的App.xaml的布局与您提到的第一个示例完全相同。我不是从BaseViewModel派生ViewModels,而是从MVVM Light派生ViewModelBase。不过我对Messenger有点迷茫。明天我会把我所有的课程都发到gander的网站上。好的!关于如何从MVVM Light派生ViewModelBase,您让我有点不知所措。但是,是的,发布你的代码,我会看一看。所以我还没有能够真正深入到你的代码太多的细节,但我从来没有得到我的ViewModelLocator工作。所以我删掉了那部分代码。相反,我将主窗口的datacontext设置为已设置的mainviewmodel。然后,可以将主窗口中的绑定绑定到“currentviewmodel”。现在您缺少的是消息传递系统。我使用NuGet获取用于MVVM轻消息传递的galasoft包。安装后,请遵循MVVM light messaging模式的示例。仅供参考:该模式将使用您的数据、消息等创建一个通用的“消息”类。封装要在该类中发送的消息。然后,创建解析该消息的函数,然后通过设置datacontex切换到适当的viewmodel
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...