开发者

page.DataContext not inherited from parent Frame?

开发者 https://www.devze.com 2023-01-13 21:20 出处:网络
开发者_如何学CI have a Page page in a Frame frame, with frame.DataContext = \"foo\". (page.Parent as Frame).DataContext is \"foo\". ok
开发者_如何学C

I have a Page page in a Frame frame, with frame.DataContext = "foo".

  • (page.Parent as Frame).DataContext is "foo". ok
  • BindingExpression for page.DataContext is null (also forced with ClearValue). ok
  • page.DataContext is null. but I expected "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?


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:

In XAML:

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

In 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;
}


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.

"Essential Windows Presentation Foundation" says: (pp. 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.

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 in Frame; however, the objects are accessible from the Content property (meaning that they aren't isolated in a security sense).

For all these reasons, Frame is most useful when we're working with external content, but it can be carefully used for application content.

That's all it has to say -- nothing about property inheritance.

"Windows Presentation Foundation Unleashed says (p. 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 the Frame.


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.

    <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.

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.

page.DataContext not inherited from parent Frame?

0

精彩评论

暂无评论...
验证码 换一张
取 消