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);
}
}
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With