首页 > 解决方案 > 从 XAML 强制 ViewModel 实例化

问题描述

我有一个视图OutputOptionsView,其中包含多个UserControls选项设置,这些设置取决于组合框的选择。

我像这样为内部创建Datacontextand :DatatemplatesUserControlsOutputOptionsView

<UserControl.Resources>
    <ResourceDictionary>
        <local:OutputOptionsViewModel x:Key="vm" />

        <DataTemplate x:Key="OptionSettings1" DataType="{x:Type views:OptionSettings1View}">
            <views:OptionSettings1View />
        </DataTemplate>

        <DataTemplate x:Key="OptionSettings2" DataType="{x:Type views:OptionSettings2View}">
            <views:OptionSettings2View />
        </DataTemplate>

        ....
    </ResourceDictionary>
</UserControl.Resources>

的显示OptionSettingsViews处理如下:

        <ContentControl Name="OutputOptionsContentControl" Content="{Binding}" >
            <ContentControl.Style>
                <Style TargetType="{x:Type ContentControl}">
                    <Setter Property="ContentTemplate" Value="{StaticResource OptionSettings1}" />
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding AvailableOptionsListSelectedIndex}" Value="1">
                            <Setter Property="ContentTemplate" Value="{StaticResource OptionSettings2}" />
                        </DataTrigger>
                        ...
                    </Style.Triggers>
                </Style>
            </ContentControl.Style>
        </ContentControl>

ItemsSourceSelectedIndexComboBox 绑定到 viewmodelOutputOptionsViewModelOutputOptionsView

<ComboBox Name="AvailableOptionsListComboBox" ItemsSource="{Binding AvailableOptionsList}" DisplayMemberPath="OptionTitle" 
                  SelectedIndex="{Binding AvailableOptionsListSelectedIndex, UpdateSourceTrigger=PropertyChanged}"/>

我的每个OptionSettings视图也都有一个 ViewModel:

<UserControl.Resources>
    <ResourceDictionary>
        <local:OptionSettings1ViewModel x:Key="vm" />
    </ResourceDictionary>
</UserControl.Resources>

<Grid DataContext="{StaticResource vm}">
...
</Grid>

现在我的问题涉及组合框的人口。我创建了一个接口,其中包含每个都继承的 OptionTitle OptionsSettingsViewModelsAvailableOptionsList组合ItemsSouce框是此接口的列表。

public List<IOutputOption> AvailableOptionsList { get; set; }

它将在OutputOptionsViewModel类的构造函数中实例化。

在每个OptionSettingsViewModel类构造函数中,我将各自添加OptionsSettingsViewModel到此列表中:

public OptionSettings1ViewModel()
{
    OutputOptionsViewModel.AvailableOptionsList.Add(this);
}

这会导致以下问题:只要 OptionSettingsViews 没有被实例化,组合框就不会被填充,但是它们不能被实例化,因为它们不能从空的组合框中被选择。因此,我希望强制实例化 OptionSettingsViews。

标签: c#wpfmvvm

解决方案


评论让我觉得,有一些基本的误解:

[Lynn Crumbling] 我会完全重新架构它以始终实例化所有视图模型,将它们嵌套在主视图模型下。您将需要它们,那么为什么不直接在主 vm 的 ctor 中启动它们呢?

[Roland Deschain] 这实际上是我目前解决它的方法,但这意味着我必须在每个选项设置视图模型的代码隐藏中设置数据上下文,这是我想尽可能避免的

因此,正如 Lynn 所说,您应该首先在主视图模型中注册子视图模型,此时不需要任何视图参与。

然后您可以DataTemplateviewmodels定义,而不是像现在这样为视图定义。

<DataTemplate DataType="{x:Type viewmodels:OptionSettings1ViewModel}">
    <views:OptionSettings1View />
</DataTemplate>

<DataTemplate DataType="{x:Type viewmodels:OptionSettings2ViewModel}">
    <views:OptionSettings2View />
</DataTemplate>

通过删除x:Key并将 更改DataType为 viewmodel 类型,将自动选择模板以显示相应类型的内容。

您的子视图的 DataContext 将从外部自动设置。不要在控件 xaml 中实例化子视图模型。

在您的 mainOutputOptionsViewModel中,您应该托管子视图模型的集合。在您的组合框中,您应该直接将此集合用作 itemssource。

然后只需删除所有复杂的模板选择 xaml 并将内容直接绑定到您选择的子视图模型:

<ContentControl
    Name="OutputOptionsContentControl"
    Content="{Binding ElementName=AvailableOptionsListComboBox,Path=SelectedItem}" />

推荐阅读