我决定使用MVVM Light库来帮助设计UI。经过大量的研究和反复试验,我还没有找到我想要的答案。我已经用谷歌搜索并阅读了我能找到的每个StackOverflow问题,但是,我的问题似乎在SO上是独一无二的。
我希望设计一个带有单个窗口的UI,并使用不同的Views / UserControls填充它。我不想在UserControls中使用共享导航栏,也不想弹出多个窗口。每个View / UserControl都应绑定到自己的ViewModel,而MainWindow将绑定到MainViewModel。
示例场景 - 具有3个UserControls的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.
Etc等。
也许我的方法并不现实,但我觉得必须这样做。我不明白如何让所有这些作品在概念上发挥作用。我的欲望绝不是独一无二的。如果您认为这是重复的问题,请重定向。欢呼声。
为了让事情更容易理解,我在下面列了一些课程。首先,我的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>
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>
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<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; }
}
}
}
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>
如果有什么不清楚,我也可以添加Model类,但我假设你可以根据发生的事情做出推断。感谢。
答案 0 :(得分:3)
所以你的方法很合理。您必须使用某些复杂的功能才能获得该功能。我不得不使用&#34; MainViewModel&#34;其中包含所有视图模型。这些视图模型的行为使得当数据上下文切换到不同的视图模型时,相应的用户控件将更改为适当的视图。 Sheridan here回答了我遵循的一个很好的例子。使用适当的数据模板连接到app.xaml,数据上下文切换将像魔术一样处理:D
我偏离Sheridan的例子(因为我不想创建一个单独的中继命令类/对象),我实际上使用mvvm light(galasoft)从我的视图模型发送消息给消息到#34; MainViewModel&#34;切换其数据上下文。可以找到使用MVVM光消息传递的一个很好的示例here。从&#34;孩子发送消息&#34;查看模型并将其注册到&#34; MainViewModel。&#34;
祝你好运!答案 1 :(得分:1)
您是否可以使用接口来填充IChildLayout? 每个ViewModel都继承了这个接口...
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(通过编辑&#34; Child&#34;属性来自它自己的ViewModel来切换布局非常重要...)
您将一个UserControl放入主窗口(在xaml中),内容被绑定到您的Child属性,然后每次更改您的Child属性时都会刷新。
<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>
在这种情况下,您的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。