Tomasz
Tomasz

Reputation: 2061

WPF ContentPresenter Content null when Visibility=Collapsed

I'm making custom control with edit/view state.

I've made 2 dependencyProperties with default styles:

<Setter Property="EditContent">
    <Setter.Value>
        <TextBox Text="{Binding ElementName=parent, Path=LocalValue}" />
    </Setter.Value>
</Setter>
<Setter Property="ViewContent">
    <Setter.Value>
        <TextBox IsEnabled="False" Text="{Binding ElementName=parent, Path=LocalValue}" />
    </Setter.Value>
</Setter>

and then, displaying these Contents depending on IsReadOnly value like this:

<Border Background="Transparent"
        MouseLeftButtonDown="UIElement_OnMouseLeftButtonDown"
        Visibility="{Binding ElementName=parent,
                                Path=IsReadOnly,
                                Converter={StaticResource BooleanToCollapsingVisibilityConverter},
                                ConverterParameter=true}">
    <ContentPresenter Content="{Binding ElementName=parent, Path=ViewContent}" />
</Border>

Problem is, that when my control loads with IsReadOnly = true, Content Property of my ContentPresenter for EditContent is null.

When I'm changing IsReadOnly to false Content of EditContent loads, but my binding does not work (like it's not evaluated).

How to re-evaluate bindings in WPF, or force ContentPresenter to load it's content on created (even if it's invisible)?

P.S. If I navigate to this ContentPresenter in Snoop (or WPF Inspector) when It's invisible - it's empty. When I navigate to it when it's visible - bindings starting to work

Upvotes: 2

Views: 1379

Answers (1)

Liero
Liero

Reputation: 27338

  1. Please, have a look at output windows while debugging. you will see errormessage describing the binding problem. wpf rule nr.1: always check output window.

  2. The reason is that your edit / view content has different NameScope, therefore ElementName does not work. However, in your Control you can set NameScope manually, by using something like:

 var currentScope = NameScope.GetNameScope(this);
 NameScope.SetNameScope((UIElement)this.EditContent, currentScope)

in your case you are using styles and styles has its own namescope, so it won't work. Imagine, that you used the style on multiple pages. What element should be used?

Sometimes you can use Source={x:Reference elementName}, but you cannot use it in direct children of the source the element, because the element does not exist yet, when the {x:Reference } is being resolved

  1. never set content-like properties inside styles. if you applied your style to more than one element, that the same TextBox from ViewContent would be added to visual tree multiple times and that throws an exception. You should use DataTemplates instead of direct content in styles

Upvotes: 1

Related Questions