如何使用TemplateBinding继承Control的所有属性

时间:2014-08-20 09:48:10

标签: wpf xaml datatemplate

我正在尝试创建我自己的控件版本,比如说TextBox,我想添加一些自定义UI。我想继承这个类,这样用户仍然可以像调用常规文本框一样调用我的特殊文本框。我有以下内容:

// MySpecialTextBox.cs

public class MySpecialTextBox : TextBox
{
    static MySpecialTextBox () { }   

    /* Some special properties */     
}

在XAML中:

<Style TargetType="{x:Type MySpecialTextBox}">        
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type MySpecialTextBox}">
                <StackPanel>
                    <Rectangle Width="100" Height="3" Fill="Pink" /> <!-- My own fancy lay-out -->
                    <TextBox Text="{TemplateBinding Text}"/>         <!-- This text box should 'inherit' ALL the properties from the caller -->
                </StackPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

我的问题是,现在,TextBox只获取您在此模板中明确设置的属性,在本例中仅为Text。我还要绑定到BackgroundForeground以及其他所有可能的属性。显然我可以做类似的事情:

<ControlTemplate TargetType="{x:Type MySpecialTextBox}">
    <StackPanel>
        <Rectangle Width="100" Height="3" Fill="Pink" />
           <TextBox Text="{TemplateBinding Text}" 
                     Background="{TemplateBinding Background}"
                     Foreground="{TemplateBinding Foreground}"
                     AcceptsReturn="{TemplateBinding AcceptsReturn}"
                     AllowDrop="{TemplateBinding AllowDrop}"
                     <!-- ETCETERA -->
                   />
    </StackPanel>
</ControlTemplate>

列出所有属性,但感觉非常低效。有没有办法一次性绑定到整个父级?

2 个答案:

答案 0 :(得分:2)

TemplateBinding是标准Binding的优化形式,大致相当于使用Binding属性设置为RelativeSource的{​​{1}}。因此,与标准RelativeSource.TemplatedParent一样,只能在单个属性上设置。来自MSDN上的TemplateBindingExtension Class页:

  

您在模板中使用Binding绑定到应用模板的控件上的

来自MSDN上的TemplateBinding Markup Extension页:

  

... TemplateBinding只有一个可设置的属性......

这意味着我们无法为其提供多个属性名称,因此它仅适用于单个属性。不幸的是,没有方便TemplateBinding影响所有属性,但即使有,我也无法想象任何简单的方法来映射哪些属性应该绑定到哪些模板属性。因此答案是“不,没有从模板化父控件继承属性值的快捷方式”。

答案 1 :(得分:1)

在另一个TextBox的模板中放置另一个TextBox元素并不是一个好主意。当您覆盖其模板时,您应该做的是始终编辑控件的默认模板。

因此,在TextBox的默认模板中,您将找到以下元素:

    <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
        <ScrollViewer x:Name="PART_ContentHost" Focusable="False" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
    </Border>

此边框负责绘制TextBox。如果您使用此部分而不是内部TextBox,那么您将拥有所有其他TextBox属性“继承”。

修改

完整的模板应该是:

 <Style TargetType="{x:Type my:MySpecialTextBox}">
     <Setter Property="Template">
         <Setter.Value>
             <ControlTemplate TargetType="{x:Type my:MySpecialTextBox}">
                 <StackPanel>
                     <Rectangle Width="100" Height="3" Fill="Pink" />
                     <!-- My own fancy lay-out -->
                     <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
                         <ScrollViewer x:Name="PART_ContentHost" Focusable="False" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
                     </Border>
                 </StackPanel>
             </ControlTemplate>
         </Setter.Value>
     </Setter>
 </Style>