Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 一个视图模型中的两个视图(WPF/MVVM)_C#_Wpf_Mvvm - Fatal编程技术网

C# 一个视图模型中的两个视图(WPF/MVVM)

C# 一个视图模型中的两个视图(WPF/MVVM),c#,wpf,mvvm,C#,Wpf,Mvvm,问题:将一个viewModel与两个不同的视图一起使用 我有一个窗口,其中有一个控件ContentControl,该控件绑定到DataContext中的一个属性,名为objectmaincontent{get;set;}。基于navigationTypeenum属性,我将其他ViewModels分配给它,以显示正确的UserControl 我需要将两个视图合并到一个视图模型中,因为我正在将一个视图模型分配给前面提到的ContentControl,所以TemplateSelector无法识别哪个视

问题:将一个viewModel与两个不同的视图一起使用

我有一个
窗口
,其中有一个控件
ContentControl
,该控件绑定到
DataContext
中的一个属性,名为
objectmaincontent{get;set;}
。基于navigationType
enum
属性,我将其他ViewModels分配给它,以显示正确的
UserControl

我需要将两个视图合并到一个视图模型中,因为我正在将一个视图模型分配给前面提到的
ContentControl
,所以
TemplateSelector
无法识别哪个视图是正确的视图,因为两者共享同一个视图模型

如果我将视图而不是ViewModel指定给
ContentControl
,则会显示正确的视图,但是没有任何命令起作用

有什么帮助吗?提前谢谢。




解决方案:基于@mm8答案和:

ManagePatientViewModel.cs

public class ManagePatientViewModel : ViewModelBase
{
    public ManagePatientViewModel (MainWindowViewModel inMainVM) : base(inMainVM) {}
} 
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);
    }
}
ViewHelper.cs

public enum ViewState
{
    SEARCH,
    CREATE,
}
MainWindowViewModel.cs

public class ManagePatientViewModel : ViewModelBase
{
    public ManagePatientViewModel (MainWindowViewModel inMainVM) : base(inMainVM) {}
} 
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
如何知道要使用哪个模板?恐怕这毫无意义

您应该使用两种不同的类型。您可以在一个公共基类中实现该逻辑,然后定义两种标记类型,这两种类型仅从该实现派生,不添加任何功能:

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}" />

...

当有两个视图类型映射到一个视图模型类型时,
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}" />

...

可能需要切换视图并保留单视图模型。 数据模板只是实例化视图的一种方法。 您可以将contentcontrol的datacontext设置为viewmodel的实例,并将视图切换为内容。因为视图是视图的责任,所以这些任务可以完全在视图中完成,而不会“破坏”mvvm。 这里有一个非常快速和肮脏的方法来说明我的意思。 我构建了两个用户控件,UC1和UC2。这些对应于您的各种患者视图。 以下是其中一个的标记:

<StackPanel>
    <TextBlock Text="User Control ONE"/>
    <TextBlock Text="{Binding HelloString}"/>
</StackPanel>
我的主窗口标记:

<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>
oneviewmodel的单个实例将被保留,并且显示的视图将被关闭。hellostring绑定并在两者中显示ok

在您的应用程序中,您需要一种更复杂的方法来设置datacontext,但此示例仅用于向您展示另一种方法的概念证明

以下是工作示例:

可能需要切换视图并保留单视图模型。 数据模板只是实例化视图的一种方法。 您可以将contentcontrol的datacontext设置为viewmodel的实例,并将视图切换为内容。因为视图是视图的责任,所以这些任务可以完全在视图中完成,而不会“破坏”mvvm。 这里有一个非常快速和肮脏的方法来说明我的意思。 我构建了两个用户控件,UC1和UC2。这些对应于您的各种患者视图。 以下是其中一个的标记:

<StackPanel>
    <TextBlock Text="User Control ONE"/>
    <TextBlock Text="{Binding HelloString}"/>
</StackPanel>
我的主窗口标记:

<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>
oneviewmodel的单个实例将被保留,并且显示的视图将被关闭。hellostring绑定并在两者中显示ok

在您的应用程序中,您需要一种更复杂的方法来设置datacontext,但此示例仅用于向您展示另一种方法的概念证明

以下是工作示例:

当有两个视图模型类型映射到一个视图类型时,TemplateSelector如何知道要使用哪个模板?这毫无意义。你应该使用两种不同的类型。谢谢你的回答@mm8,这就是我提问的原因,我不知道如何继续,或者我应该改变什么。你能告诉我正确的方向吗?我发布了一个答案。当有两个视图模型类型映射到一个视图类型时,TemplateSelector怎么知道要使用哪个模板?这毫无意义。你应该使用两种不同的类型。谢谢你的回答@mm8,这就是我提问的原因,我不知道如何继续,或者我应该做些什么。你能告诉我正确的方向吗?我发布了一个答案。我可能解释错了,我需要的是一个视图模型的两个不同视图,不是将两个视图模型放在一个视图中。我已经测试过了,我也有同样的问题,命令不起作用。问题是我已经有了两个不同的ViewModel,这就是为什么我一开始没有理解你的观点。一个是搜索,另一个是创建。我已经将它们合并到
ManagePatientViewModel
中,我应该对这两个视图都使用它。基本上,我认为
TemplateSelector
可以一次选择哪个视图是正确的。基本上,我必须简化我们所有的视图和ViewsModel,使用一个视图模型(ManagePatientViewModel)创建两个视图(CreateView和SearchView)是有意义的。我想发布每个视图的代码,但是extense和Stack抱怨“代码太多”。我认为拥有两个具有相同ViewModel的视图是很容易的,我会忘记这一点。我已经更新了我的问题,我也应用了您的解决方案,但它不起作用,视图更改为正确的视图,但ViewModel中绑定的命令没有被调用。对于专家来说这可能很容易,但我只是WPF的新手。问题是TemplateSelector.SelectTemplate.Item是