WPF - ContentPresenter无法绑定到UserControl的Content属性。

3

好的,我相对新于WPF,在我的用户控件中出现了一个问题,其中包含一个自定义按钮。

一切都正常工作,直到我尝试将自定义按钮的内容绑定到用户控件的内容上。

用户控件代码:

<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:OP"
mc:Ignorable="d"
x:Class="OP.GamepadButton"
x:Name="GamePadBtn"
d:DesignWidth="100" d:DesignHeight="100">
<UserControl.Resources>
    <Style x:Key="GamepadButtonStyle" TargetType="{x:Type Button}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Grid>
                        <Rectangle x:Name="rectangle" Fill="{TemplateBinding Background}" StrokeThickness="1" Opacity="0.8" Stroke="{TemplateBinding BorderBrush}"/>
                        <ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                        RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" 
                        VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsFocused" Value="True"/>
                        <Trigger Property="IsDefaulted" Value="True"/>
                        <Trigger Property="IsMouseOver" Value="True"/>
                        <Trigger Property="IsPressed" Value="True"/>
                        <Trigger Property="IsEnabled" Value="False"/>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</UserControl.Resources>

<Grid x:Name="LayoutRoot" Background="Transparent">
    <Grid.RowDefinitions>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <Button Content="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:GamepadButton}}, Path=Content}" 
    Background="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:GamepadButton}}, Path=Background}" 
    BorderBrush="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:GamepadButton}}, Path=BorderBrush}" 
    Grid.Row="1" Style="{DynamicResource GamepadButtonStyle}" />
</Grid>

我在MainWindow中以以下方式声明用户控件:

并且我在MainWindow中以以下方式声明用户控件:

<local:GamepadButton Height="60" Width="60" Background="#DAF0FC" BorderBrush="#2c3e50" Content="Button"/>

结果如下所示:

Result 1

我还注意到,由于某种原因,这也会破坏BorderBrush绑定,但不会破坏Background绑定。


如果我不为Usercontrol声明任何内容属性并直接设置按钮内容,则代码可以正常工作:

UserControl:

<Button Content="Button" 
    Background="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:GamepadButton}}, Path=Background}" 
    BorderBrush="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:GamepadButton}}, Path=BorderBrush}" 
    Grid.Row="1" Style="{DynamicResource GamepadButtonStyle}" />

主窗口:

<local:GamepadButton Height="60" Width="60" Background="#DAF0FC" BorderBrush="#2c3e50" />

这样我就得到了想要的按钮样式:

结果2


所以我的问题是:

我如何使按钮的ContentPresenter绑定到用户控件声明的内容?

1个回答

2
你面临的问题是无法从内容内部绑定到该内容。你的用户控件中的按钮是控件的当前内容。在你的输出窗口中,你会看到以下内容。
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='OP.GamepadButton', AncestorLevel='1''. BindingExpression:Path=Tag; DataItem=null; target element is 'Button' (Name=''); target property is 'Content' (type 'Object')
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='OP.GamepadButton', AncestorLevel='1''. BindingExpression:Path=Background; DataItem=null; target element is 'Button' (Name=''); target property is 'Background' (type 'Brush')
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='OP.GamepadButton', AncestorLevel='1''. BindingExpression:Path=BorderBrush; DataItem=null; target element is 'Button' (Name=''); target property is 'BorderBrush' (type 'Brush')

如果您将其更改为其他属性,比如标签,那么您的样式将被正确应用。

我认为您可以只使用样式来解决您的任务,但如果您确实需要新的UserControl,则可以直接从按钮继承它,而不是UserControl。


谢谢!完美地解决了问题,现在我感觉自己太蠢了,竟然没想到这个。 - Nobbe
跟进问题,我相当确定我需要它成为一个用户控件(因为未来计划如何使用它),但如果GamepadButton直接从button继承而不是usercontrol,那么在使用它们方面,GamepadButton:UserControl和GamepadButton:Button有什么区别? - Nobbe
使用上不会有任何区别,但在功能上可能会有一些小差异。GamepadButton:Button 可以用于直接从 XAML 中嵌套内容,这有时非常有用。另一方面,如果要实现相同的功能,GamepadButton:UserControl 就需要一些依赖属性,因为正如之前所看到的,您无法为用户控件指定内容,因为它已经预定义了一个。 - Vladimir Mezentsev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接