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}"
выполнить каскад.