尝试创建一个自定义面板,但得到一个:该对象已经有一个子项,无法添加“Button”编译器异常

时间:2013-07-30 17:24:24

标签: wpf styles scrollviewer contentcontrol contentpresenter

我对wpf很新。

我正在尝试制作一个带有一些奇特设计边框的自定义面板。 我得到了一切工作但只有我在自定义面板中只有一个控件。 如果我尝试添加多个,那么我会得到以下异常:

  

对象'BordersPanel'已经有一个孩子,无法添加'Button'。 'BordersPanel'只能接受一个孩子。

我花了很多时间试图在网上找到解决方案,但到目前为止还没有。 所以我转向社区寻求帮助。

面板样式:

    <Style
    TargetType="{x:Type local:BordersPanel}">
    <Setter
        Property="Template">
        <Setter.Value>
            <ControlTemplate
                TargetType="{x:Type local:BordersPanel}">
                <Grid Margin="0,0,0,0">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="10.8" />
                        <RowDefinition Height="*" />
                        <RowDefinition Height="10.8" />
                    </Grid.RowDefinitions>
                    <local:Border
                        x:Name="topBorder"
                        Grid.Row="0"
                        Margin="0"
                        HorizontalAlignment="Stretch"
                        VerticalAlignment="top"
                        BlocksSize="{TemplateBinding BlocksSize}"
                        Width="Auto"
                        Height="10.8"/>

                    <ScrollViewer
                        Grid.Row="1"
                        HorizontalScrollBarVisibility="Auto"
                        VerticalScrollBarVisibility="Auto">
                        <ContentPresenter
                            Cursor="{TemplateBinding Cursor}"
                            HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                            Margin="{TemplateBinding Padding}"
                            VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                            Content="{TemplateBinding Content}"
                            ContentTemplate="{TemplateBinding ContentTemplate}"/>
                    </ScrollViewer>
                    <local:Border
                        x:Name="bottomBorder"
                        Grid.Row="2"
                        Margin="0"
                        VerticalAlignment="Bottom"
                        HorizontalAlignment="Stretch"
                        BlocksSize="{TemplateBinding BottomBlocksSize}"
                        Width="Auto"
                        Height="10.8"/>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

背后的C#代码:

    class BordersPanel : ContentControl
{
    public static readonly DependencyProperty BlocksSizeProperty =
        DependencyProperty.Register("BlocksSize", typeof(string), typeof(BordersPanel));

    public static readonly DependencyProperty BottomBlocksSizeProperty =
        DependencyProperty.Register("BottomBlocksSize", typeof(string), typeof(BordersPanel));

    private Border topBorder;

    private Border bottomBorder;

    protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
    {
        base.OnPropertyChanged(e);

        if (e.Property == BordersPanel.BlocksSizeProperty)
        {
            BottomBlocksSize = BlocksSize + ";T";
        }
    }

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        topBorder = GetTemplateChild("topBorder") as Border;
        bottomBorder = GetTemplateChild("bottomBorder") as Border;
    }

    static BordersPanel()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(BordersPanel),
            new FrameworkPropertyMetadata(typeof(BordersPanel)));
    }

    public BordersPanel()
    {
        SizeChanged += new SizeChangedEventHandler(Border_SizeChanged);
    }

    public string BlocksSize
    {
        get
        {
            return (string)GetValue(BlocksSizeProperty);
        }
        set
        {
            SetValue(BlocksSizeProperty, value);
        }
    }

    protected string BottomBlocksSize
    {
        get
        {
            return (string)GetValue(BottomBlocksSizeProperty);
        }
        set
        {
            SetValue(BottomBlocksSizeProperty, value);
        }
    }

    private void Border_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        double available = Width;
        if (Double.IsNaN(available) == true)
        {
            available = ActualWidth;
        }

        if (topBorder != null)
        {
            topBorder.Width = available;
        }
        if (bottomBorder != null)
        {
            bottomBorder.Width = available;
        }
    }
}

这就是我使用它的方式:

    <local:BordersPanel
        BlocksSize="LL50;ML50;RU"
        Height="208" Canvas.Left="213" Canvas.Top="56.82" Width="428.5">
        <local:BinarySquares Margin="0,0,10,15" HorizontalAlignment="Right" VerticalAlignment="Bottom" d:LayoutOverrides="Width, Height"/>
        <Button Content="Button" HorizontalAlignment="Stretch" Height="300"/>
    </local:BordersPanel>

我很确定我错过了一些非常明显的东西,但这是显而易见的事情,你看得越多,他们就越躲避你......

按照他们的方式,如果您认为有更好的方法来做我所做的事情(使用绑定,面板,......),欢迎提出意见。 :)

非常清楚: 在我使用之前:

    <local:Border
        Margin="0"
        VerticalAlignment="top"
        BlocksSize="LL50;ML200;RU"
        Width="Auto" Height="10.8" HorizontalAlignment="Stretch" d:LayoutOverrides="Width"/>
    <local:BinarySquares Margin="0,0,10,15" HorizontalAlignment="Right" VerticalAlignment="Bottom" d:LayoutOverrides="Width, Height"/>
    <Grid  Margin="8,14.8,8,24">
        <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
            <Canvas x:Name="pnl_Content5" Margin="0,0,0,0">
                <Button Content="Button" HorizontalAlignment="Stretch" Canvas.Left="77" Canvas.Top="44"/>
            </Canvas>
        </ScrollViewer>
    </Grid>
    <local:Border
        Margin="0"
        VerticalAlignment="Bottom"
        BlocksSize="LL50;ML200;RU;T"
        Width="Auto" Height="10.8" HorizontalAlignment="Stretch"/>

每次使用面板时,我都会反复使用此代码。

显然,我在前面的代码块中编写的内容更短,更易于维护。 (最起码,我是这么想的) 这就是为什么我用边框制作这个自定义面板以避免重复代码。

1 个答案:

答案 0 :(得分:1)

我找到了一个有效的解决方案。 这不是我想要的,但它足够接近它会做的。 我只是在BordersPanel实例中放置了一个网格声明。 我宁愿不必这样做,但我猜这样,它实际上允许我在面板内使用任何类型的布局。

            <local:BordersPanel
                BlocksSize="LL50;ML50;RU"
                Margin="0">
                <Grid>
                    <local:BinarySquares Margin="0,0,10,15" HorizontalAlignment="Right" VerticalAlignment="Bottom" d:LayoutOverrides="Width, Height"/>
                    <Button Content="Button" HorizontalAlignment="Stretch" Height="300"/>
                </Grid>
            </local:BordersPanel>