在ContentControl中忽略了对RowDefinition.Height的TemplateBinding

时间:2011-06-26 13:19:13

标签: silverlight grid dependency-properties contentcontrol templatebinding

说明 我有一个自定义内容控件,我试图通过依赖属性启用一些外部设置。基本上它是一个装饰器面板,有两个网格行,上面一个是标题,下面一个是内容(通过ContentPresenter)。

有3个项目绑定到模板(通过TemplateBinding),HeaderHeightTextSizeHeader(每个项目都具有相应类型的依赖项属性)。 / p>

问题: 虽然两个绑定工作完美(即使在设计时),但第三个绑定没有。 FontSize="{TemplateBinding TextSize}"Text="{TemplateBinding Header}"绑定有效,但<RowDefinition Height="{TemplateBinding HeaderHeight}" /> 不起作用

网格将行的高度50/50分开,无论我将HeaderHeight属性设置为哪个值。它甚至不采用DP元数据中的默认值。

问题: 这种情况有什么问题?为什么其他两个绑定没有问题,这个表现就像没有绑定一样?

注意: 如果我在构造函数中设置DataContext = this并将{TemplateBinding HeaderHeight}替换为{Binding HeaderHeight},问题就会消失并且按预期工作。但我想知道为什么我不需要与其他绑定做同样的事情来使它们工作。

XAML(Themes / Generic.xaml):

<Style TargetType="local:KaiPanel">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:KaiPanel">
                <Grid x:Name="LayoutRoot">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="{TemplateBinding HeaderHeight}" />
                        <RowDefinition />
                    </Grid.RowDefinitions>

                    <Grid Grid.Row="0">
                        <Border>
                            <TextBlock FontSize="{TemplateBinding TextSize}" 
                                       Text="{TemplateBinding Header}" />
                        </Border>
                    </Grid>

                    <Grid Grid.Row="1">
                        <Border>
                            <ContentPresenter />
                        </Border>
                    </Grid>

                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

内容控制(C#):

public class KaiPanel : ContentControl
{
    public KaiPanel()
    {
        this.DefaultStyleKey = typeof(KaiPanel);
    }

    public static readonly DependencyProperty TextSizeProperty =
        DependencyProperty.Register("TextSize", typeof(double), typeof(KaiPanel), new PropertyMetadata(15.0));

    public double TextSize
    {
        get { return (double)GetValue(TextSizeProperty); }
        set { SetValue(TextSizeProperty, value); }
    }

    public static readonly DependencyProperty HeaderProperty =
        DependencyProperty.Register("Header", typeof(String), typeof(KaiPanel), new PropertyMetadata(""));

    public String Header
    {
        get { return (String)GetValue(HeaderProperty); }
        set { SetValue(HeaderProperty, value); }
    }

    public static readonly DependencyProperty HeaderHeightProperty =
        DependencyProperty.Register("HeaderHeight", typeof(GridLength), typeof(KaiPanel), new PropertyMetadata(new GridLength(40)));

    public GridLength HeaderHeight
    {
        get { return (GridLength)GetValue(HeaderHeightProperty); }
        set { SetValue(HeaderHeightProperty, value); }
    }
}

自定义控件使用情况(XAML):

<UserControl ...>

    <Grid x:Name="LayoutRoot">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="150" />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>

        <StackPanel x:Name="buttonsStackPanel" Grid.Column="0" VerticalAlignment="Center">
            <!-- Some buttons here -->
        </StackPanel>

        <Grid Grid.Column="1">
            <controls:KaiPanel x:Name="contentPanel">
                <navigation:Frame x:Name="contentFrame" Source="KP">
                    <navigation:Frame.UriMapper>
                        <uriMapper:UriMapper>
                            <uriMapper:UriMapping Uri="KP" MappedUri="/Views/Kornelijepetak.xaml" />
                            <uriMapper:UriMapping Uri="KAI" MappedUri="/Views/KaiNetwork.xaml" />
                        </uriMapper:UriMapper>
                    </navigation:Frame.UriMapper>
                </navigation:Frame>
            </controls:KaiPanel>
        </Grid>
    </Grid>
</UserControl>

2 个答案:

答案 0 :(得分:0)

可悲的是,您尝试做的事情似乎不仅仅需要一个数据绑定。 RowDefinition不是FrameworkElement的子类,它与MSDN Silverlight data binding documentation中指定的任何其他条件都不匹配,因此不能用作绑定的目标。

你想做的是可能的,但不幸的是它涉及更多的代码。

首先,将主网格(我称之为mainGrid)的字段添加到KaiPanel类。然后,覆盖此类中的OnApplyTemplate方法以从模板中获取主Grid,并在mainGrid字段中保留对其的引用:

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
        mainGrid = GetTemplateChild("LayoutRoot") as Grid;
        SetHeaderRowHeight();
    }

这会调用一个方法来更新网格第一行的高度。该方法如下:

    private void SetHeaderRowHeight()
    {
        if (mainGrid != null)
        {
            mainGrid.RowDefinitions[0].Height = HeaderHeight;
        }
    }

我承认我并非100%确定在设置DP后调用OnApplyTemplate。似乎是这种情况(快速测试似乎证实了这一点),但我能找到的所有支持都是this post on the Silverlight forums。如果您发现情况并非如此,则需要在HeaderHeight DP上注册一个PropertyChangedCallback,它也会调用此SetHeaderRowHeight方法。

另见http://forums.silverlight.net/forums/t/76992.aspx#183089

答案 1 :(得分:0)

改用 RelativeSource 和 TemplatedParent:

<RowDefinition Height="{Binding RelativeSource={RelativeSource TemplatedParent},
 Path=HeaderHeight}" />

这里解释TemplateBinding和RelativeSource TemplatedParent的区别: WPF TemplateBinding vs RelativeSource TemplatedParent