说明
我有一个自定义内容控件,我试图通过依赖属性启用一些外部设置。基本上它是一个装饰器面板,有两个网格行,上面一个是标题,下面一个是内容(通过ContentPresenter
)。
有3个项目绑定到模板(通过TemplateBinding),HeaderHeight
,TextSize
和Header
(每个项目都具有相应类型的依赖项属性)。 / 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>
答案 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
方法。
答案 1 :(得分:0)
改用 RelativeSource 和 TemplatedParent:
<RowDefinition Height="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=HeaderHeight}" />
这里解释TemplateBinding和RelativeSource TemplatedParent的区别: WPF TemplateBinding vs RelativeSource TemplatedParent