ContentPresenter Visibility binding inside Grid not working?
Asked Answered
G

4

5

I have a following grid:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    ...
    <ContentPresenter Grid.Row="1" Content="{Binding Path=PredictiveWorkspace}"
                      Visibility="{Binding Path=ShowPredictiveWorkspace, 
                      Converter={StaticResource boolToVisibility}}"/>
    <ContentPresenter Grid.Row="1" Content="{Binding Path=M2Workspace}"
                      Visibility="{Binding Path=ShowStandardWorkspace, 
                      Converter={StaticResource boolToVisibility}}"/>
    ...
</Grid>

Those two ContentPresenters has the same Grid.Row definded because only one of them should be visible at once. I have following boolToVisibility converter:

[ValueConversion(typeof(bool), typeof(System.Windows.Visibility))]
public class BoolToVisibilityConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if ((bool)value)
        {
            return System.Windows.Visibility.Visible;
        }
        else
            return System.Windows.Visibility.Collapsed;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return null;
    }
}

And there's the problem: both ContentPresenters are visible! I noticed also that only ShowPredictiveWorkspace property is being read by a app. Breakpoint set on ShowStandardWorkspace getter is never called. I guess it some stupid mistake but I really can't find it.

EDIT:

public bool ShowStandardWorkspace
    {
        get { return this._showStandardWorkspace; }
        set
        {
            this._showStandardWorkspace = value;
            this.OnPropertyChanged(() => this.ShowStandardWorkspace);
        }
    }
Giordano answered 4/12, 2013 at 14:18 Comment(2)
Could this be related to the fact that at start M2Workspace is null? I think it shouldnt as visibility of ContentPresenter shouldn't be related to content it presents right?Giordano
You can verify this assumption by binding both presenters to the same content.Schwarzwald
C
15

This is because it does not work to bind visibility with a converter on the ContentPresenter element.

If you change the ContentPresenter to a ContentControl it will work to bind the visibility property with a converter, and then you don't have to nest it within another element.

This is apparently because ContentPresenter is a light weight element that is meant to be used within a ControlTemplate.

From MSDN (with my highlighting):

You typically use the ContentPresenter in the ControlTemplate of a ContentControl to specify where the content is to be added. Every ContentControl type has a ContentPresenter in its default ControlTemplate.

When a ContentPresenter object is in a ControlTemplate of a ContentControl, the Content, ContentTemplate, and ContentTemplateSelector properties get their values from the properties of the same names of the ContentControl. You can have the ContentPresenter property get the values of these properties from other properties of the templated parent by setting the ContentSource property or binding to them.

Ceja answered 15/1, 2015 at 14:21 Comment(0)
G
4

I have been searching a lot plus I made some tests and I'm pretty sure you cannot control the visibility of a contentpresenter. Plus - if the ViewModel that is going to be presented by the ContentPresenter is null when view is being showed - it does not even read the property using by boolToVisibilityConverter.

I made a simple workaround - I put ContentPresenter inside a Grid (you can use other type of container obviously) and bound Visibility of the Grid to the boolean properties. It works perfectly.

Giordano answered 5/12, 2013 at 12:8 Comment(2)
Generally, you can control visibility of ContentPresenter. The problem is that setting Content property also sets DataContext of ContentPresenter to the same value, thus breaking all bindings that expect DataContext to be inherited from the parent control.Citified
Eugene's comment gave me the idea to try subscribing to contentPresnter's DataContextChanged event. Alas, that event is never fired (specifically with CalendarDayButtonStyle controltemplate in DatePicker - but probably the same behavior everywhere)Curzon
A
1

You should use the AncestorType. The DataContext isn't the same, when you use the ContentPresenter, but you can navigate up in the Visual Tree to find it. In Your case:

Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type Grid}}, Path=ShowStandardWorkspace}"

Where Grid is the first ancestor by default, and its DataContext is used. If you need a second, third etc. ancestor, use the AncestorLevel property with an int value. The converter is fine, I think.

Americanism answered 4/12, 2013 at 14:47 Comment(2)
Well, that's not true.Schwarzwald
@Schwarzwald - you are right. It is not true what Rudolfking wrote. I checked (just in case) but it was pretty obvious, because the first contentpresenter reads the property without problem.Giordano
C
0

possible sources of error:

  • spelling error ShowStandardWorkspace
  • OnPropertyChanged("ShowStandardWorkspace") not raised in property setter
  • ShowStandardWorkspace property simply not set to false
  • maybe wrong DataContext for the 2nd ContentPresenter
Chimera answered 4/12, 2013 at 14:34 Comment(3)
I checked. 1. Spelling error - not, I copied/pasted all. 2. OnPropertyChanged is raised, more thatn that - the handler is not null so sth is binded right? 3. It is false. 4. How the context could be wrong if it's in the same viewmodel as 1st ContentPresenter and it's the same view?Giordano
well then it should work :) can you check the binding at runtime with Snoop.Chimera
Thanks for the tip about Snoop, very interesting app. I'm using boolToVisibilityConverter also at the same View earlier and I noticed the in Snoop 'Visibility' property is highlighted green. But - in both problematic ContentPresenters - it's highlighted red. Weird. I have to look carefully through it again.Giordano

© 2022 - 2024 — McMap. All rights reserved.