首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >WPF -无法将ContentPresenter中控件的属性绑定到父控件

WPF -无法将ContentPresenter中控件的属性绑定到父控件
EN

Stack Overflow用户
提问于 2012-10-22 04:35:17
回答 2查看 1.7K关注 0票数 3

我有一个在表单中使用的自定义控件,这个控件结合了标签和文本框。当窗体处于只读模式时,控件将更改为显示标签而不是文本框。为此,我为控件定义了一个内容模板,如下所示:

代码语言:javascript
复制
<Style TargetType="{x:Type Controls:FormFieldControl}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="200"/>
                        <ColumnDefinition Width="200"/>
                    </Grid.ColumnDefinitions>

                    <AdornerDecorator Grid.Column="1"
                                      Visibility="{Binding RelativeSource={RelativeSource AncestorType=Controls:FormFieldControl}, 
                                                   Path=IsReadOnly, 
                                                   Converter={StaticResource BooleanToInverseVisibilityConverter}, 
                                                   Mode=OneWay}">
                        <ContentPresenter Name="ContentPresenter" />
                    </AdornerDecorator>

                    <AdornerDecorator Grid.Column="1"
                                      Visibility="{Binding RelativeSource={RelativeSource AncestorType=FormFieldControl}, 
                                      Path=IsReadOnly, Converter={StaticResource BooleanToVisibilityConverter}, 
                                      Mode=OneWay}">
                        <ContentPresenter Name="ReadOnlyContentPresenter" />
                    </AdornerDecorator>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

ReadOnlyContentPresenter的内容是一个应用了以下样式的标签:

代码语言:javascript
复制
<Style x:Key="ReadOnlyFormFieldControl" TargetType="{x:Type Label}">
    <Setter Property="Width" Value="400" />
        <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Controls:FormFieldControl}, 
                               Path=ReadOnlyWidth, 
                               Converter={StaticResource IsSetConverter}}"
                     Value="True">
            <Setter Property="Width" 
                    Value="{Binding RelativeSource={RelativeSource AncestorType=Controls:FormFieldControl}, Path=ReadOnlyWidth}" />
        </DataTrigger>
    </Style.Triggers>
</Style>

这对于大约80个控件很有效,但是当我向窗体添加更多控件时,标签样式中的绑定无法找到源(错误4):

代码语言:javascript
复制
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='MyProject.Controls.FormFieldControl', AncestorLevel='1''. BindingExpression:Path=ReadOnlyWidth; DataItem=null; target element is 'Label' (Name=''); target property is 'ReadOnlyWidth' (type 'Double?')

应用于控件的可编辑部分的样式也会发生同样的情况。我认为这个问题与正在处理的控件数量有关,如果我将控件编号81 (失败)的代码移到控件编号80 (工作)的正上方,则控件编号81中的绑定现在有效,但控件编号80中的绑定失败。我这样做的几个控制,和行为是一致的。

我仍然不清楚AdornerDecorator究竟是如何工作的,在调查的过程中,我发现这个question提到了装饰层中有144个以上装饰器的问题,所以我删除了代码中的AdornerDecorator,结果却发现发生在第81号或更高版本控件上的绑定问题现在也发生在我所有的FormFieldControl上。

最后,我决定尝试在我的控件模板中使用ContentControl的而不是ContentPresenter的。这对表单中的所有控件都很有效。我知道ContentPresenterContentControl的轻量级形式,它比ContentControl更适合在内容模板中使用。然而,我不太明白为什么在使用ContentPresenter时绑定会失败,而在使用ContentControl时会起作用。

我还发现奇怪的是,只有有限的一组控件可以工作,并且当不使用AdornerDecorator时,它们都不会找到绑定源。

有没有人遇到过类似的事情?我是不是对ContentPresenter做错了什么?或者,如果这是意料之中的行为,有人能帮我理解一下发生了什么吗?

任何想法都是值得感谢的。

EN

回答 2

Stack Overflow用户

发布于 2012-11-28 01:01:41

从你的问题中不清楚标签是只显示文本框中的内容,还是必须显示自定义标签,但如果是前者,那么我认为您应该像前面提到的那样使用IsReadOnly属性。

您可以定义一个自定义ControlTemplate,它在TextBox为只读时隐藏它的背景和边框,使它看起来就像是一个Label

试试这个简单的例子:

代码语言:javascript
复制
<StackPanel>
    <StackPanel.Resources>
        <Style x:Key="{x:Type TextBox}"
               TargetType="{x:Type TextBoxBase}">
            <Setter Property="SnapsToDevicePixels"
                    Value="True" />
            <Setter Property="OverridesDefaultStyle"
                    Value="True" />
            <Setter Property="KeyboardNavigation.TabNavigation"
                    Value="None" />
            <Setter Property="FocusVisualStyle"
                    Value="{x:Null}" />
            <Setter Property="MinWidth"
                    Value="120" />
            <Setter Property="MinHeight"
                    Value="20" />
            <Setter Property="AllowDrop"
                    Value="true" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type TextBoxBase}">
                        <Border Name="Border"
                                CornerRadius="2"
                                Padding="2"
                                Background="AliceBlue"
                                BorderBrush="Black"
                                BorderThickness="1">
                            <ScrollViewer Margin="0"
                                          x:Name="PART_ContentHost" />
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsReadOnly"
                                     Value="True">
                                <Setter TargetName="Border"
                                        Property="Background"
                                        Value="Transparent" />
                                <Setter TargetName="Border"
                                        Property="BorderBrush"
                                        Value="Transparent" />
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </StackPanel.Resources>
    <TextBox Margin="50,25"
             Name="tb" />

    <Button Content="Switch modes"
            Margin="50,25"
            Click="Button_Click" />
</StackPanel>

您将需要以下按钮单击处理程序来切换只读模式:

代码语言:javascript
复制
private void Button_Click(object sender, RoutedEventArgs e)
{
    tb.IsReadOnly = !tb.IsReadOnly;
}

以下是TextBox可编辑时的结果:

这就是TextBox在只读时的样子。

票数 0
EN

Stack Overflow用户

发布于 2014-10-21 18:24:43

我认为原因可能是这样的:

代码语言:javascript
复制
var contentPresenter = new ContentPresenter { Content = new Button() };
var contentControl = new ContentControl { Content = new Button() };
if ((contentPresenter.Content as FrameworkElement).Parent == null)
    Debug.WriteLine("ContentPresenter won't let you get ancestors");
if ((contentControl.Content as FrameworkElement).Parent != null)
    Debug.WriteLine("ContentControl will let you get ancestors");

这两行都会显示,这意味着contentPresenter是少数未正确设置"Parent“属性的FrameworkElement之一。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13001939

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档