WPF MVVM:推迟渲染视图直到设置 DataContext

WPF MVVM: Postpone rendering of View until DataContext is set

在我们的 MVVM 应用程序中,在一个视图中,DataContext 最初为 null,稍后设置。 视图首先在没有设置 DataContext 的情况下呈现,因此对于绑定,使用默认值或 FallbackValues。一旦设置了 DataContext 并更新了所有绑定,这会导致 UI 发生很多变化。 UI 有点 'bouncy',我可以想象相当多的 CPU 周期被浪费了。 有没有一种方法可以推迟视图的呈现,直到设置 DataContext?

我们为 ViewModel 查找视图的代码:

<ContentControl
     DataContext="{Binding Viewodel}"
     Content="{Binding}"
     Template="{Binding Converter={converters:ViewModelToViewConverter}}"/>

ViewModelToViewConverter.cs:

  public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
  {
     ViewModel viewModel = value as ViewModel;

     if (viewModel == null)
     {
        return null;
     }

     string modelName = viewModel.ToString();

     string mappingId = viewModel.MappingId;
     if (!string.IsNullOrEmpty(mappingId))
     {
        modelName += "_" + mappingId;
     }

     ControlTemplate controlTemplate = new ControlTemplate();

     MappingEntry mappingEntry = ApplicationStore.SystemConfig.GetMappingEntryOnModelName(modelName); // lookup View definition for ViewModel

     Type type = mappingEntry != null ? mappingEntry.ViewType : null;

     if (type != null)
     {
        controlTemplate.VisualTree = new FrameworkElementFactory(type);
     }
     else
     {
        Logger.ErrorFormat("View not found: {0}", modelName);
     }

     return controlTemplate;
  }

是的,你可以做到

  1. 使用 FrameworkElement.DataContextChanged 事件。

  2. 使用Trigger

    示意图示例;

    <ContentControl>
    <ContentControl.Resources>
        <DataTemplate x:Key="MyTmplKey">
            <TextBlock Text="Not null"/>
        </DataTemplate>
        <DataTemplate x:Key="DefaultTmplKey">
            <StackPanel>
                <TextBlock Text="null"/>
                <Button Content="Press" Click="Button_Click_1"/>
            </StackPanel>
        </DataTemplate>
    </ContentControl.Resources>
    <ContentControl.Style>
        <Style TargetType="ContentControl">
            <Setter Property="ContentTemplate" Value="{StaticResource MyTmplKey}"/>
            <Style.Triggers>
                <Trigger Property="DataContext" Value="{x:Null}">
                    <Setter Property="ContentTemplate" Value="{StaticResource DefaultTmplKey}"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </ContentControl.Style>
    </ContentControl>