DataTemplate не обновляется после переключения на объект того же типа данных

У меня есть следующие 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>

Это прекрасно работает до тех пор, пока модель представления не попытается изменить свойство ContentViewModel с одного FilledContentViewModel на новое FilledContentViewModel, после чего содержимое ContentControl не обновляется. При переключении с EmptyContentViewModel на FilledContentViewModel или наоборот работает.

Конечно, простое обновление всего существующего FilledContentViewModel было бы одним из решений. Но я думаю, что это может быстро запутаться, и что просто создать новый ViewModel с правильным контекстом и переключить его было бы более элегантно.

Кто-нибудь знает способ обновить содержимое DataTemplate?


person Dima    schedule 01.01.2016    source источник
comment
Вы что-то делаете в Loaded событии FilledMainWindow? Или вы используете одноразовые привязки, которые хотите обновить?   -  person Brannon    schedule 01.01.2016
comment
@Yeah69 привязан к FilledMainWindow данным и будет реагировать соответствующим образом, если вы измените его DataContext с одного FilledContentViewModel на другое?   -  person dkozl    schedule 01.01.2016
comment
@Yeah69, когда вы измените Content на другой FilledContentViewModel, он изменит DataContext и переоценит ContentTemplate и снова установит его на DataTemplate для FilledContentViewModel, но для WPF это тот же шаблон, поэтому это не изменение, поэтому он не будет воссоздавать пользовательский элемент управления, и фактически изменится только его DataContext . Проблема угадывания где-то здесь.   -  person dkozl    schedule 01.01.2016
comment
@Brannon Я не использую событие Loaded для FilledMainWindow, и я также не использую одноразовые привязки в рассматриваемом проекте.   -  person Dima    schedule 02.01.2016
comment
@dkozl Я не знаю. Еще не пробовал. Я попытаюсь изменить DataContext FilledMainWindow напрямую (не через DataTemplate) и сообщу вам результат.   -  person Dima    schedule 02.01.2016
comment
@dkozl Это тоже мое предположение. Я предполагаю, что ContentControl просто ищет DataType, и если он все тот же, и реагирует только на изменение DataType. В этом проекте FilledContentViewModel получает класс отображения ORM (с использованием Dapper). Итак, если во время выполнения открывается другая база данных, я подумал, что будет проще изменить путь к базе данных в классе картографа и внедрить его в новый FilledContentViewModel вместо того, чтобы обновлять все в существующем.   -  person Dima    schedule 02.01.2016
comment
@dkozl Теперь я проверил то, что вы просили, заменив весь ContentControl, который я разместил в вопросе, на <usercontrols:FilledMainWindow DataContext="{Binding ContentViewModel}" x:Name="MainContent" />. И тогда переключение FilledContentViewModel объектов сработало как положено. Проблема в том, что DataTemplate для EmptyContentViewModel, где я хочу разместить что-то вроде стартовой страницы в будущем, теперь отклонен.   -  person Dima    schedule 02.01.2016


Ответы (1)


Я столкнулся с аналогичной проблемой с элементом управления ContentPresenter, где я переключал Content на новый экземпляр того же типа модели представления, и он не обновлялся. Я обнаружил почти ту же проблему, с которой столкнулся на social.msdn.microsoft.com, и решение, которое я в итоге использовал, заключалось в создании пользовательского ContentControl / ContentPresenter, которое было опубликовано как часть ответа social.msdn.microsoft.com:

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;
        }
    }
}
person Cole W    schedule 16.01.2021