Roland Deschain
Roland Deschain

Reputation: 2830

Force ViewModel Instantiation from XAML

I have a View OutputOptionsView which holds several UserControls with options settings which are displayed depending on the selection of a combobox.

I create the Datacontext and Datatemplates for the UserControls within OutputOptionsView like this:

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

The display of the OptionSettingsViews is handled as follows:

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

ItemsSource and SelectedIndex of the ComboBox are bound to the viewmodel class OutputOptionsViewModel of the OutputOptionsView:

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

Each of my OptionSettings view also gets a ViewModel:

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

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

Now my Issue concerns the population of the population of the combobox. I created an Interface containing the OptionTitle which each OptionsSettingsViewModels inherits. AvailableOptionsList which is the ItemsSouce for the combobox is a List of this Interface.

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

It will be instantiated within the Constructor of the OutputOptionsViewModelclass.

Within each of the OptionSettingsViewModel class constructors I add the respective OptionsSettingsViewModel to this List:

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

This leads to the following Problem: The combobox isn't populated as long as the OptionSettingsViews aren't instantiated, but they can't be instantiated , because they can't be selected from the empty combobox. Therefore I'm looking to force the Instantiation of the OptionSettingsViews.

Upvotes: 0

Views: 428

Answers (1)

grek40
grek40

Reputation: 13438

The comments made me think, there is some basic misunderstanding:

[Lynn Crumbling] I'd completely re-architect this to always instantiate all of the viewmodels, nesting them under the mainviewmodel. You're going to need them, so why not just spin them up in the ctor of the main vm?

and

[Roland Deschain] that is actually how I solved it at the moment, however this means that I have to set the datacontext in the code-behind of each optionssettingsviewmodel, which was what I wanted to avoid if possible

So, as Lynn said, you should start by registering the sub-viewmodels within the main viewmodel, no need for any view involvement at this point.

Then you can define DataTemplate for the viewmodels, not for the views as you do now.

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

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

By removing the x:Key and changing the DataType to the viewmodel type, the templates will be automatically selected to display content of the respective type.

The DataContext of your sub-views will be automatically set from the outside. Do not instantiate a sub-viewmodel within the controls xaml.

In your main OutputOptionsViewModel, you should host a collection of the sub-viewmodels. In your combobox, you should directly use this collection as itemssource.

Then just drop all the complicated template selection xaml and directly bind the content to your selected sub-viewmodel:

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

Upvotes: 1

Related Questions