网格内的 ContentPresenter 可见性绑定不起作用?

Posted

技术标签:

【中文标题】网格内的 ContentPresenter 可见性绑定不起作用?【英文标题】:ContentPresenter Visibility binding inside Grid not working? 【发布时间】:2013-12-21 01:54:52 【问题描述】:

我有以下网格:

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

这两个ContentPresenters 具有相同的Grid.Row 定义,因为一次只能看到其中一个。 我有以下boolToVisibility 转换器:

[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;
    

问题是:ContentPresenters 都是可见的!我还注意到只有ShowPredictiveWorkspace 属性被应用程序读取。在ShowStandardWorkspace getter 上设置的断点永远不会被调用。 我猜这是一个愚蠢的错误,但我真的找不到它。

编辑:

public bool ShowStandardWorkspace
    
        get  return this._showStandardWorkspace; 
        set
        
            this._showStandardWorkspace = value;
            this.OnPropertyChanged(() => this.ShowStandardWorkspace);
        
    

【问题讨论】:

这可能与开始时M2Workspace 为空有关吗?我认为 ContentPresenter 的可见性不应该与其呈现的内容相关,对吗? 您可以通过将两个演示者绑定到相同的内容来验证此假设。 【参考方案1】:

可能的错误来源:

拼写错误 ShowStandardWorkspace 属性设置器中未引发 OnPropertyChanged("ShowStandardWorkspace") ShowStandardWorkspace 属性根本没有设置为 false 可能是第二个 ContentPresenter 的 DataContext 错误

【讨论】:

我查过了。 1. 拼写错误 - 不是,我全部复制/粘贴了。 2. OnPropertyChanged 被提出,更多的是 - 处理程序不为空,所以绑定了对吗? 3. 是假的。 4. 如果上下文与第一个 ContentPresenter 在同一个视图模型中并且它是同一个视图,那么上下文怎么可能是错误的? 那么它应该可以工作 :) 你能在运行时用 Snoop 检查绑定吗? 感谢有关 Snoop 的提示,非常有趣的应用程序。我之前也在同一个视图中使用boolToVisibilityConverter,我注意到 Snoop 中的“可见性”属性以绿色突出显示。但是 - 在两个有问题的ContentPresenters 中 - 它都以红色突出显示。诡异的。我得再仔细看一遍。【参考方案2】:

您应该使用AncestorType。 DataContext 不一样,当您使用 ContentPresenter 时,您可以在 Visual Tree 中向上导航以找到它。在你的情况下:

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

默认情况下,Grid 是第一个祖先,使用它的DataContext。如果您需要第二个、第三个等祖先,请使用 AncestorLevel 属性和 int 值。 我认为转换器很好。

【讨论】:

嗯,这不是真的。 @Somedust - 你是对的。鲁道夫金写的不是真的。我检查了(以防万一),但很明显,因为第一个 contentpresenter 读取属性没有问题。【参考方案3】:

我已经搜索了很多,而且我做了一些测试,我很确定你无法控制 contentpresenter 的可见性。另外 - 如果在显示视图时将由 ContentPresenter 呈现的 ViewModel 为空 - 它甚至不会读取 boolToVisibilityConverter 使用的属性。

我做了一个简单的解决方法 - 我将 ContentPresenter 放在 Grid 中(您显然可以使用其他类型的容器)并将 GridVisibility 绑定到布尔属性。效果很好。

【讨论】:

一般来说,您可以控制 ContentPresenter 的可见性。问题是设置 Content 属性也会将 ContentPresenter 的 DataContext 设置为相同的值,从而破坏了所有期望 DataContext 从父控件继承的绑定。【参考方案4】:

这是因为将可见性与 ContentPresenter 元素上的转换器绑定不起作用。

如果您将ContentPresenter 更改为ContentControl,它将可以将可见性属性与转换器绑定,然后您不必将其嵌套在另一个元素中。

这显然是因为ContentPresenter 是一个轻量级元素,旨在用于ControlTemplate

From MSDN(我的突出显示):

您通常在 ControlTemplate 中使用 ContentPresenter ContentControl 指定要添加内容的位置。每一个 ContentControl 类型默认有一个 ContentPresenter 控制模板。

当 ContentPresenter 对象位于 ContentControl 的 ControlTemplate、Content、ContentTemplate 和 ContentTemplateSelector 属性从 ContentControl 的同名属性。你可以拥有 ContentPresenter 属性从中获取这些属性的值 通过设置 ContentSource 模板化父级的其他属性 属性或绑定到它们。

【讨论】:

以上是关于网格内的 ContentPresenter 可见性绑定不起作用?的主要内容,如果未能解决你的问题,请参考以下文章

更改 QCalendarWidget 网格可见性/厚度

在 WPF 中动态更改网格的可见性

如何切换网格布局中的小部件可见性?

如何在自定义 wpf 控件上绑定数据网格列的可见性?

WPF ComboBoxItem 内的折叠可见性

非原子时,C++ 成员更新关键部分内的可见性