1

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

有 3 个项目绑定到模板(通过 TemplateBinding)HeaderHeightTextSizeHeader(每个项目都有其适当类型的依赖属性)。

问题: 虽然其中两个绑定工作得很好(即使在设计时),但第三个却不行。和绑定有效,FontSize="{TemplateBinding TextSize}"无效Text="{TemplateBinding Header}"<RowDefinition Height="{TemplateBinding HeaderHeight}" />

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

问题: 这个场景有什么问题?为什么其他两个绑定可以毫无问题地工作,而这个则表现得好像根本没有绑定?

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

XAML(主题/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>
4

2 回答 2

0

可悲的是,您尝试做的似乎不仅仅是一个数据绑定。 RowDefinition不是 FrameworkElement 的子类,并且它不匹配MSDN Silverlight 数据绑定文档中指定的任何其他条件,因此它不能用作绑定的目标。

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

首先,将主网格的字段(我称之为mainGrid)添加到您的KaiPanel班级。然后,重写OnApplyTemplate此类中的方法以从模板中获取 main并在您的字段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% 确定OnApplyTemplate在 DP 设置后调用它。似乎情况确实如此(快速测试似乎证实了这一点),但我能找到支持这一点的只有Silverlight 论坛上的这篇帖子。如果您发现情况并非如此,则需要在 DP 上注册一个 PropertyChangedCallback,该HeaderHeightDP 也会调用此SetHeaderRowHeight方法。

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

于 2011-06-26T21:11:31.863 回答
0

改用 RelativeSource 和 TemplatedParent:

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

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

于 2021-04-21T06:42:23.523 回答