ConditionRacer
ConditionRacer

Reputation: 4498

Don't create new view each time with DataTemplate/DataType

I have something like this:

<Window>
    <Window.Resources>
       <DataTemplate DataType="{x:Type local:VM1}">
          <!-- View 1 Here -->
       </DataTemplate>

       <DataTemplate DataType="{x:Type local:VM2}">
          <!-- View 2 here -->
       </DataTemplate>
    <Window.Resources>

    <ContentPresenter Content="{Binding}"/>
</Window>

This will automatically swap out the view as I bind different viewmodels, which is very handy.

However, I have one view with a tabcontrol and many subviews. Each subview has several visual parts that are configured by a custom xml file (complex business case). Each time this view is created, the xml file is parsed which causes a small (1-2 second) delay. It's enough of a delay to be annoying and make the UI feel sluggish.

Is there a way to use the DataTemplate pattern without destroying and recreating the view each time a viewmodel is bound? I'd rather not change the viewmodel if possible.

Upvotes: 5

Views: 652

Answers (2)

Dmitry
Dmitry

Reputation: 2062

You could wrap your VM into an additional class. Your DataTemplates will decide on the type of the Wrapper class but the real implementation will be exposer through a property of this Wrapper. When this property will change the DataTemplate wont be reloaded but all the bindings will be refreshed.

Wrapper class:

public class WrapperVM1:INotifyPropertyChanged
{
    public Content VM1 { get{...} set{...} }
}

public class WrapperVM2:INotifyPropertyChanged
{
    public Content VM2 { get{...} set{...} }
}

Now your data templates will describe wrapper class representations:

<DataTemplate DataType="{x:Type local:WrapperVM1}">
   <TextBlock Text={Binding Content.SomPropertyInVM1}"/>
</DataTemplate>

<DataTemplate DataType="{x:Type local:WrapperVM2}">
   <TextBlock Text={Binding Content.SomPropertyInVM2}"/>
</DataTemplate>

As you can see if you substitute the Content property of the wrapper with a new instance of VM this won't recreate the view but all bindings will update. However if you need to switch to other type of VM you will have to substitute the Wrapper class by the appropriate Wrapper.

Upvotes: 0

robertos
robertos

Reputation: 1796

For this case the easiest solution is to have the two views always there and change which one is visible. You can use a converter to change the visibility based on the type of the data context

<View1 Visibility="{Binding Converter={StaticResource TypeToVisibilityConverter, ConverterParameter=VM1}" />
<View2 Visibility="{Binding Converter={StaticResource TypeToVisibilityConverter, ConverterParameter=VM2}" />

And the converter will check if the type matches with the parameter to return Visible, or Collapsed otherwise.

Upvotes: 2

Related Questions