page.DataContext не наследуется от родительского фрейма?

У меня есть страница page в рамке frame, с frame.DataContext = "foo",

  • (page.Parent as Frame).DataContext является "foo", Хорошо
  • BindingExpression для page.DataContext является null (также принудительно с ClearValue). Хорошо
  • page.DataContext является null, но я ожидал "фу"!

Почему DataContext не наследуется? Насколько я понимаю фрейм- песочницы с контентом. Но я не смог найти никаких документов об этом поведении - кто-нибудь может указать мне место, где это упоминается?

3 ответа

Решение

Чтобы ответить на ваш вопрос о документации такого поведения: это не документация Microsoft, но у меня есть пара книг WPF, в которых оба упоминают об этом.

" Essential Windows Presentation Foundation" говорит: (стр. 160-161)

Существуют две интересные модели для размещения судоходного контента: изолированный хостинг и интегрированный хостинг.

При изолированном хостинге контент не является доверенным и работает в полностью изолированной (изолированной) среде. Вот как содержимое WPF размещается при запуске в системном веб-браузере в качестве приложения браузера XAML. Для перехода к другому приложению или контенту HTML эта модель изолированного хостинга поддерживается Frame объект.

Интегрированный хостинг, в котором мы хотим, чтобы контент работал как часть нашего приложения, в системе вообще не поддерживается. когда Frame переходя к контенту в приложении, мы получаем странный гибрид изолированного и интегрированного поведения. Frame изолирует его содержимое от своего стиля (и стиля его родителя), но не от стиля приложения. События не всплывают из контента в Frame; Тем не менее, объекты доступны из Content свойство (это означает, что они не изолированы в смысле безопасности).

По всем этим причинам Frame Наиболее полезно, когда мы работаем с внешним контентом, но его можно осторожно использовать для контента приложения.

Это все, что нужно сказать - ничего о наследовании имущества.

" Windows Presentation Foundation Unleashed говорит (стр. 95):

Frame Элемент управления содержит произвольный контент, как и все другие элементы управления контентом, но он изолирует контент от остального пользовательского интерфейса. Например, свойства, которые обычно наследуются в дереве элементов, останавливаются при достижении Frame,

Вы специально не спрашивали, как вы можете сделать эту работу, только почему это не по умолчанию. Однако, если вы хотите, чтобы ваши страницы наследовали DataContext фрейма, вы можете сделать это:

В XAML:

<Frame Name="frame"
       LoadCompleted="frame_LoadCompleted"
       DataContextChanged="frame_DataContextChanged"/>

В коде позади:

private void frame_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
    UpdateFrameDataContext(sender, e);
}
private void frame_LoadCompleted(object sender, NavigationEventArgs e)
{
    UpdateFrameDataContext(sender, e);
}
private void UpdateFrameDataContext(object sender, NavigationEventArgs e)
{
    var content = frame.Content as FrameworkElement;
    if (content == null)
        return;
    content.DataContext = frame.DataContext;
}

Построить ответ @ Джо-Уайта для тех, кто хочет знать, как сделать Frame каскадировать DataContextЯ упомяну, что это также может быть выполнено только в XAML.

    <Style TargetType="{x:Type Frame}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Frame}">
                    <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}">
                        <ContentPresenter x:Name="PART_FrameCP" DataContext="{TemplateBinding DataContext}"/>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Style.Triggers>
            <Trigger Property="NavigationUIVisibility" Value="Visible">
                <Setter Property="Template" Value="{StaticResource FrameNavChromeTemplateKey}"/>
            </Trigger>
            <MultiTrigger>
                <MultiTrigger.Conditions>
                    <Condition Property="JournalOwnership" Value="OwnsJournal"/>
                    <Condition Property="NavigationUIVisibility" Value="Automatic"/>
                </MultiTrigger.Conditions>
                <Setter Property="Template" Value="{StaticResource FrameNavChromeTemplateKey}"/>
            </MultiTrigger>
        </Style.Triggers>
    </Style>

Для тех, кто не знаком с WPF, вы можете поместить этот XAML в App.xaml файл, чтобы он переопределил все Frame элементы управления в вашем приложении, которые выбирают стиль по умолчанию. Это означает, что вам не нужно писать конкретный код каждый раз, когда вы используете новый Frame,

Я использовал VisualStudio 2015 Visual Designer (см. Рис. Ниже), чтобы создать большую часть XAML выше, а затем добавил DataContext="{TemplateBinding DataContext}" выполнить каскад.

VS2015 дизайнер

Другие вопросы по тегам