DataTemplate does not refresh after switching to an object of same DataType
Asked Answered
H

1

6

I have following ControlTemplate:

<ContentControl Content="{Binding ContentViewModel}">
   <ContentControl.Resources>
      <DataTemplate DataType="{x:Type viewModel:FilledContentViewModel}">
         <usercontrols:FilledMainWindow x:Name="MainContent" />
      </DataTemplate>
      <DataTemplate DataType="{x:Type viewModel:EmptyContentViewModel}">
         <!-- todo: Something like a StartPage here -->
      </DataTemplate>
   </ContentControl.Resources>
</ContentControl>

This works great until the view model tries to change the ContentViewModel property from one FilledContentViewModel to a new FilledContentViewModel, then the content of the ContentControl does not refresh. If switching from EmptyContentViewModel to FilledContentViewModel or the other way around, it works.

Of course, just updating everything in the existing FilledContentViewModel instead would be one solution. But I think it could get messy quick and that just creating a new ViewModel with the right context and switch it would be more elegant.

Does anybody know a way to let the content of the DataTemplate refresh?

Height answered 1/1, 2016 at 15:57 Comment(7)
You're doing something in the Loaded event of the FilledMainWindow? Or you're using one-time bindings that you want refreshed?Vedi
@Yeah69 is FilledMainWindow data bound and will react accordingly if you change its DataContext from one FilledContentViewModel to another?Scarecrow
@Yeah69 when you change Content to another FilledContentViewModel it will change DataContext and re-evaluate ContentTemplate and set it again to DataTemplate for FilledContentViewModel but for WPF it's same template therefore not a change so it will not recreate user control and effectively only its DataContext will change. Guessing problem is somewhere here.Scarecrow
@Vedi I don't use the Loaded event of the FilledMainWindow and I also don't use one-time bindings anyway in the project of concern.Height
@Scarecrow I don't know. Didn't try it yet. I'll try to change the DataContext of the FilledMainWindow directly (not through DataTemplate) and will tell you the result.Height
@Scarecrow This would be my guess, too. I assume that the ContentControl just looks up the DataType and if it is still the same and only reacts if the DataType changes, too. In this project the FilledContentViewModel gets an ORM mapper class (using Dapper) injected. So, if another database is opened on runtime I thought it would be easier to change the path to the database in the mapper class and inject it into a new FilledContentViewModel instead of updating everything in the existing one.Height
@Scarecrow Now, I tested what you have asked by replacing the whole ContentControl, which I posted in the question by <usercontrols:FilledMainWindow DataContext="{Binding ContentViewModel}" x:Name="MainContent" />. And then the switching of the FilledContentViewModel objects worked as intended. The problem is: The DataTemplate for the EmptyContentViewModel, where I want to put something like a start page in future is dismissed now.Height
E
1

I ran into a similar problem with the ContentPresenter control where I would switch the Content to be a new instance of the same view model type and it wasn't refreshing. I found nearly the identical problem I was running into on social.msdn.microsoft.com and the solution I ended up using was to create a custom ContentControl / ContentPresenter that was posted as part of the social.msdn.microsoft.com answer:

https://social.msdn.microsoft.com/Forums/vstudio/en-US/6bc0a0ed-cb98-4863-a09e-5c99d0ddf90e/mvvm-contentcontrols-view-will-not-refresh?forum=wpf

public class MyContentControl : ContentControl
{
   
    public MyContentControl()
    {
        this.ContentTemplateSelector = new MyDataTemplateSelector();
    }


    class MyDataTemplateSelector : DataTemplateSelector
    {

        public override DataTemplate SelectTemplate(object item, DependencyObject container)
        {
            var declaredDataTemplate = FindDeclaredDataTemplate(item, container);
            var wrappedDataTemplate = WrapDataTemplate(declaredDataTemplate);
            return wrappedDataTemplate;
        }

        private static DataTemplate WrapDataTemplate(DataTemplate declaredDataTemplate)
        {
            var frameworkElementFactory = new FrameworkElementFactory(typeof(ContentPresenter));
            frameworkElementFactory.SetValue(ContentPresenter.ContentTemplateProperty, declaredDataTemplate);
            var dataTemplate = new DataTemplate();
            dataTemplate.VisualTree = frameworkElementFactory;
            return dataTemplate;
        }

        private static DataTemplate FindDeclaredDataTemplate(object item, DependencyObject container)
        {
            var dataTemplateKey = new DataTemplateKey(item.GetType());
            var dataTemplate = ((FrameworkElement)container).FindResource(dataTemplateKey) as DataTemplate;
            if (dataTemplate == null)
                throw new Exception("datatemplate not found");
            return dataTemplate;
        }
    }
}
Elonore answered 16/1, 2021 at 13:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.