问题:使用一个具有两个不同视图的viewModel。
我有一个Window
,其中一个控件ContentControl
绑定到DataContext
中的一个名为Object MainContent {get;set;}
的属性。基于navigationType enum
属性,我将其他ViewModel分配给它以显示正确的UserControl
。
我需要将两个视图合并到一个ViewModel中,并且因为我将ViewModel分配给之前提到的ContentControl
,TemplateSelector
无法识别哪个是正确的视图,因为两个共享相同的viewModel
如果我将视图而不是ViewModel分配给ContentControl
,则会显示正确的视图,但是,这些命令不起作用。
任何帮助?提前致谢。
解决方案:基于@ mm8答案和https://stackoverflow.com/a/5310213/2315752:
ManagePatientViewModel.cs
public class ManagePatientViewModel : ViewModelBase
{
public ManagePatientViewModel (MainWindowViewModel inMainVM) : base(inMainVM) {}
}
ViewHelper.cs
public enum ViewState
{
SEARCH,
CREATE,
}
MainWindowViewModel.cs
public ViewState State {get;set;}
public ManagePatientViewModel VM {get;set;}
private void ChangeView(ViewState inState)
{
State = inState;
// This is need to force the update of Content.
var copy = VM;
MainContent = null;
MainContent = copy;
}
public void NavigateTo (NavigationType inNavigation)
{
switch (inNavigationType)
{
case NavigationType.CREATE_PATIENT:
ChangeView(ViewState.CREATE);
break;
case NavigationType.SEARCH_PATIENT:
ChangeView(ViewState.SEARCH);
break;
default:
throw new ArgumentOutOfRangeException(nameof(inNavigationType), inNavigationType, null);
}
}
MainWindow.xaml
<DataTemplate x:Key="CreateTemplate">
<views:CreateView />
</DataTemplate>
<DataTemplate x:Key="SearchTemplate">
<views:SearchView/>
</DataTemplate>
<TemplateSelector x:Key="ViewSelector"
SearchViewTemplate="{StaticResource SearchTemplate}"
CreateViewTemplate="{StaticResource CreateTemplate}"/>
<ContentControl
Grid.Row="1"
Content="{Binding MainContent}"
ContentTemplateSelector="{StaticResource ViewSelector}" />
TemplateSelector.cs
public class TemplateSelector : DataTemplateSelector
{
public DataTemplate SearchViewTemplate {get;set;}
public DataTemplate CreateViewTemplate {get;set;}
}
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
if (!(item is SelectLesionViewModel vm))
{
return null;
}
switch (vm.ViewType)
{
case ViewState.CREATE:
return CreateViewTemplate;
case ViewState.SEARCH:
return SearchViewTemplate;
default:
return null;
}
}
}
答案 0 :(得分:2)
当有两种视图类型映射到单个视图模型类型时,TemplateSelector
如何知道要使用哪个模板?这毫无意义我害怕。
您应该使用两种不同的类型。您可以在公共基类中实现逻辑,然后定义两个仅从此实现派生的标记类型,并且不添加任何功能:
public class ManagePatientViewModel { */put all your code in this one*/ }
//marker types:
public class SearchPatientViewModel { }
public class CreatePatientViewModel { }
此外,如果您从模板中删除x:Key
属性,则您真的不需要模板选择器:
<DataTemplate DataType="{x:Type viewModels:SearchPatientViewModel}">
<views:SearchPatientView />
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:CreatePatientViewModel}">
<views:CreatePatientView />
</DataTemplate>
...
<ContentControl
Grid.Row="1"
Content="{Binding MainContent}" />
答案 1 :(得分:2)
可能要求是切换视图并保留一个视图模型。 Datatemplating只是实例化视图的一种方法。 您可以将contentcontrol的datacontext设置为viewmodel的实例,并将视图切换为内容。由于视图是一种视图责任,因此这些任务可以在视图中完全完成而不会打破&#34; MVVM。 这是一个非常快速和肮脏的方法,说明我的意思。 我构建了两个用户控件,UC1和UC2。这些对应于您的各种患者观点。 这是一个标记:
<StackPanel>
<TextBlock Text="User Control ONE"/>
<TextBlock Text="{Binding HelloString}"/>
</StackPanel>
我创建了一个简单的视图模型。
public class OneViewModel
{
public string HelloString { get; set; } = "Hello from OneViewModel";
}
我的主窗口标记:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel>
<Button Content="UC1" Click="UC1_Click"/>
<Button Content="UC2" Click="UC2_Click"/>
</StackPanel>
<ContentControl Name="parent"
Grid.Column="1"
>
<ContentControl.DataContext>
<local:OneViewModel/>
</ContentControl.DataContext>
</ContentControl>
</Grid>
点击事件会切换内容: private void UC1_Click(object sender,RoutedEventArgs e) { parent.Content = new UC1(); }
private void UC2_Click(object sender, RoutedEventArgs e)
{
parent.Content = new UC2();
}
保留oneviewmodel的单个实例,并显示所显示的视图。 hellostring绑定并显示两者都正常。
在你的应用程序中,你需要一种更复杂的方法来设置datacontext,但这个样本纯粹是为了向你展示另一种方法的概念证明。