Search code examples
c#wpfxamldatatemplatecontentcontrol

WPF: Switching Views with DataTemplates - How to have view change its DataContext automatically?


Thanks in advance for any help I can get! I'll jump right in!

Assume I have the following XAML. I left out parts that wouldn't be needed to hopefully keep this easier to read.

The TreeView is populated in the MainWindow code behind by created an ObservableCollection of MainViewModelBaseobjects. The Properties of those objects are based on a XML file read in at start by the main windows code being.

This makes the items of the TreeView of type MainViewModelBase. From there I want to use the string "Type" property (which was read in from the XML) of the SelectedItem of the Treeview to display a UserControl on the right side of the screen. Based on TONs of googling, the below code uses DataTemplates to accomplish the view switches.

My question is this. The UserControl that I want to populate needs to be be binded to another XML file, and the name of that XML file will be based on the string called Name stored in the MainViewModelBase. The code below gets the new view to show up, but I can't figure out how to get the new Views DataContext to be set to the XML. There must be some way though the content control to do this. I think that when you use a DataTemplate to do the switch, the resulting view inherits the DataContext of the ViewModel type that "created" it. But I think the DataContext isn't set until after the constructor of the view is done. Thus I can't have the constructor of the view open the XML based on the string "name" of the MainViewModel. Is there a way to have the DataContext updated after the fact? Thanks!

Another note, there is lots of items in the TreeView, thus lots of XMLs. I don't want to have all XMLs in memory at once, only when the view that needs it needs it.

Finally, I am new to WPF, so I apologize in advance if part of my above question are dumb or completely confusing. I am asking them from the perspective of someone new to the technology.

Note: I know I can bind the TreeView directly to the initial XML, and I may switch to that in the future, I'm not sure yet. Most examples online were using ObservableCollections of VeiwModel objects, so it was easier to learn this way.

<Window x:Class="WpfApplication3.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Window.Resources>

    <DataTemplate x:Key="BlankTemplate" DataType="{x:Type ViewModel:MainViewModelBase}">
        <View:BlankControl/>
    </DataTemplate>

    <DataTemplate x:Key="ParagraphTemplate" DataType="{x:Type ViewModel:MainViewModelBase}">
        <View:ParagraphControl/>
    </DataTemplate>

    <DataTemplate DataType="{x:Type ViewModel:MainViewModelBase}">
        <ContentControl Content="{Binding}">
            <ContentControl.Style>
                <Style TargetType="{x:Type ContentControl}">
                    <Setter Property="ContentTemplate" Value="{StaticResource BlankTemplate}" />
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding Type}" Value="Paragraph">
                            <Setter Property="ContentTemplate" Value="{StaticResource ParagraphTemplate}" />
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </ContentControl.Style>
        </ContentControl>
    </DataTemplate>

</Window.Resources>

<DockPanel>

    <Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width=".5*"/>
        <ColumnDefinition Width=".5*"/>
    </Grid.ColumnDefinitions>

    <TreeView Name="navigationPane" Grid.Column="0"/>

    <ContentControl Grid.Column="1" Content="{Binding ElementName=navigationPane, Path=SelectedItem}"/>

</Grid>


Solution

  • After some more Googling, I found a great project on codeproject that describes how to use the view model idea to make a load on command treeview. What I really liked about this was that it showed me how to use the INotifyPropertyChanged stuff to bind the isSelected property to something in the view model that could be used todo the XML loading etc.

    I know this may seem basic to you WPF gurus out there, but this was so helpful in explaining to me how to really use the ViewModel pattern.

    http://www.codeproject.com/Articles/26288/Simplifying-the-WPF-TreeView-by-Using-the-ViewMode