MVVM Light - 用户控件作为视图

pio*_*sco 5 c# xaml user-controls mvvm 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.
Run Code Online (Sandbox Code Playgroud)

或者,另外

 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.
Run Code Online (Sandbox Code Playgroud)

等等

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


为了使事情更容易理解,我在下面列出了一些课程.首先,我的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>
Run Code Online (Sandbox Code Playgroud)

MainWindow.xaml

<Window x:Class="Bobcat_BETA.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Bobcat - Version:0.00"
    DataContext="{Binding Main, Source={StaticResource Locator}}">
<Grid>
    <ContentControl Content="{Binding CurrentView}"/>
</Grid>
Run Code Online (Sandbox Code Playgroud)

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;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

SavedScenariosViewModel.cs

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

    }
}
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

如果有什么不清楚的地方,我也可以添加Model类,但我认为你可以根据发生的事情进行推断.谢谢.

Stu*_*nna 3

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

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

祝你好运!