I have a Page page
in a Frame frame
, with frame.DataContext = "foo"
.
我在Frame框架中有一个页面页面,其中frame.DataContext =“foo”。
-
(page.Parent as Frame).DataContext
is"foo"
. ok - (page.Parent as Frame).DataContext是“foo”。好
- BindingExpression for
page.DataContext
isnull
(also forced with ClearValue). ok - page.DataContext的BindingExpression为null(也强制使用ClearValue)。好
-
page.DataContext
isnull
. but I expected "foo"! - page.DataContext为null。但我期待“foo”!
Why isn't the DataContext inherited? As far as I understand the Frame sandboxes the content. But I couldn't find any documentation of this behavior - can anyone point me to a place where this is mentioned?
为什么DataContext没有继承?据我所知,Frame沙箱的内容。但我找不到任何关于这种行为的文件 - 有人能指出我提到这个的地方吗?
3 个解决方案
#1
13
To answer your question about documentation of this behavior: It's not Microsoft documentation, but I have a couple of WPF books that both mention this.
要回答有关此行为文档的问题:这不是Microsoft文档,但我有几本WPF书籍都提到了这一点。
"Essential Windows Presentation Foundation" says: (pp. 160-161)
“Essential Windows Presentation Foundation”说:(第160-161页)
There are two interesting models for hosting navigable content: isolated hosting and integrated hosting.
托管可导航内容有两个有趣的模型:独立托管和集成托管。
With isolated hosting the content is not trusted and is run in a completely isolated (sandboxed) environment. This is how WPF content is hosted when running in the system Web browser as a XAML Browser Application. For navigation to another application or HTML content, this isolated hosting model is supported with a
Frame
object.使用隔离托管,内容不受信任,并且在完全隔离(沙盒)环境中运行。这是在系统Web浏览器中作为XAML浏览器应用程序运行时托管WPF内容的方式。对于导航到其他应用程序或HTML内容,Frame对象支持此独立主机模型。
Integrated hosting, in which we want the content to behave as part of our application, is not supported at all in the system. When
Frame
navigates to content within the application, we get an odd hybrid of isolated and integrated behavior.Frame
isolates its content from its style (and its parent's style), but not from the application's style. Events don't bubble from the content inFrame
; however, the objects are accessible from theContent
property (meaning that they aren't isolated in a security sense).我们希望内容在我们的应用程序中运行的集成主机在系统中根本不受支持。当Frame导航到应用程序中的内容时,我们会得到孤立和集成行为的奇怪混合。 Frame将其内容与其样式(及其父级样式)隔离开来,但不是从应用程序的样式中隔离出来。事件不会从Frame中的内容冒泡;但是,可以从Content属性访问对象(这意味着它们在安全意义上不是隔离的)。
For all these reasons,
Frame
is most useful when we're working with external content, but it can be carefully used for application content.出于所有这些原因,Frame在我们处理外部内容时最有用,但它可以小心地用于应用程序内容。
That's all it has to say -- nothing about property inheritance.
这就是它所要说的 - 没有关于财产继承的事。
"Windows Presentation Foundation Unleashed says (p. 95):
“Windows Presentation Foundation Unleashed说(第95页):
The
Frame
control holds arbitrary content, just like all other content controls, but it isolates the content from the rest of the UI. For example, properties that would normally be inherited down the element tree stop when they reach theFrame
.Frame控件保存任意内容,就像所有其他内容控件一样,但它将内容与UI的其余部分隔离开来。例如,通常在元素树下继承的属性在到达Frame时停止。
#2
22
You didn't specifically ask how you could make this work, only why it doesn't by default. However, if you do want your Pages to inherit the Frame's DataContext, you can do this:
你没有具体询问如何使这项工作,只是为什么它没有默认。但是,如果您确实希望Pages继承Frame的DataContext,则可以执行以下操作:
In XAML:
在XAML中:
<Frame Name="frame"
LoadCompleted="frame_LoadCompleted"
DataContextChanged="frame_DataContextChanged"/>
In codebehind:
在codebehind中:
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;
}
#3
2
To build upon @Joe-White's answer for those who want to know of ways to make the Frame
cascade the DataContext
, I'll mention that this can also be performed in XAML only.
为了建立@ Joe-White的答案,为那些想知道如何使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>
For those that are new to WPF, you can put this XAML in the App.xaml
file so that it will override all Frame
controls in your application that pick up the default style. This means you don't have to write specific code-behind each time you use a new Frame
.
对于那些刚接触WPF的人,可以将此XAML放在App.xaml文件中,以便它覆盖应用程序中拾取默认样式的所有Frame控件。这意味着每次使用新Frame时都不必编写特定的代码隐藏。
I used the VisualStudio 2015 Visual Designer (see pic below) to create the bulk of the XAML above and then added the DataContext="{TemplateBinding DataContext}"
to perform the cascade.
我使用VisualStudio 2015可视设计器(见下图)创建上面的大量XAML,然后添加DataContext =“{TemplateBinding DataContext}”来执行级联。
#1
13
To answer your question about documentation of this behavior: It's not Microsoft documentation, but I have a couple of WPF books that both mention this.
要回答有关此行为文档的问题:这不是Microsoft文档,但我有几本WPF书籍都提到了这一点。
"Essential Windows Presentation Foundation" says: (pp. 160-161)
“Essential Windows Presentation Foundation”说:(第160-161页)
There are two interesting models for hosting navigable content: isolated hosting and integrated hosting.
托管可导航内容有两个有趣的模型:独立托管和集成托管。
With isolated hosting the content is not trusted and is run in a completely isolated (sandboxed) environment. This is how WPF content is hosted when running in the system Web browser as a XAML Browser Application. For navigation to another application or HTML content, this isolated hosting model is supported with a
Frame
object.使用隔离托管,内容不受信任,并且在完全隔离(沙盒)环境中运行。这是在系统Web浏览器中作为XAML浏览器应用程序运行时托管WPF内容的方式。对于导航到其他应用程序或HTML内容,Frame对象支持此独立主机模型。
Integrated hosting, in which we want the content to behave as part of our application, is not supported at all in the system. When
Frame
navigates to content within the application, we get an odd hybrid of isolated and integrated behavior.Frame
isolates its content from its style (and its parent's style), but not from the application's style. Events don't bubble from the content inFrame
; however, the objects are accessible from theContent
property (meaning that they aren't isolated in a security sense).我们希望内容在我们的应用程序中运行的集成主机在系统中根本不受支持。当Frame导航到应用程序中的内容时,我们会得到孤立和集成行为的奇怪混合。 Frame将其内容与其样式(及其父级样式)隔离开来,但不是从应用程序的样式中隔离出来。事件不会从Frame中的内容冒泡;但是,可以从Content属性访问对象(这意味着它们在安全意义上不是隔离的)。
For all these reasons,
Frame
is most useful when we're working with external content, but it can be carefully used for application content.出于所有这些原因,Frame在我们处理外部内容时最有用,但它可以小心地用于应用程序内容。
That's all it has to say -- nothing about property inheritance.
这就是它所要说的 - 没有关于财产继承的事。
"Windows Presentation Foundation Unleashed says (p. 95):
“Windows Presentation Foundation Unleashed说(第95页):
The
Frame
control holds arbitrary content, just like all other content controls, but it isolates the content from the rest of the UI. For example, properties that would normally be inherited down the element tree stop when they reach theFrame
.Frame控件保存任意内容,就像所有其他内容控件一样,但它将内容与UI的其余部分隔离开来。例如,通常在元素树下继承的属性在到达Frame时停止。
#2
22
You didn't specifically ask how you could make this work, only why it doesn't by default. However, if you do want your Pages to inherit the Frame's DataContext, you can do this:
你没有具体询问如何使这项工作,只是为什么它没有默认。但是,如果您确实希望Pages继承Frame的DataContext,则可以执行以下操作:
In XAML:
在XAML中:
<Frame Name="frame"
LoadCompleted="frame_LoadCompleted"
DataContextChanged="frame_DataContextChanged"/>
In codebehind:
在codebehind中:
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;
}
#3
2
To build upon @Joe-White's answer for those who want to know of ways to make the Frame
cascade the DataContext
, I'll mention that this can also be performed in XAML only.
为了建立@ Joe-White的答案,为那些想知道如何使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>
For those that are new to WPF, you can put this XAML in the App.xaml
file so that it will override all Frame
controls in your application that pick up the default style. This means you don't have to write specific code-behind each time you use a new Frame
.
对于那些刚接触WPF的人,可以将此XAML放在App.xaml文件中,以便它覆盖应用程序中拾取默认样式的所有Frame控件。这意味着每次使用新Frame时都不必编写特定的代码隐藏。
I used the VisualStudio 2015 Visual Designer (see pic below) to create the bulk of the XAML above and then added the DataContext="{TemplateBinding DataContext}"
to perform the cascade.
我使用VisualStudio 2015可视设计器(见下图)创建上面的大量XAML,然后添加DataContext =“{TemplateBinding DataContext}”来执行级联。