如何在ControlTemplate中通过TemplateBinding绑定TextBox的Text属性
表单行控件效果参考

报错根因
ContentControl 类型本身没有定义Text依赖属性,直接在XAML中给该类型实例赋值Text属性,必然触发「成员不存在或不可访问」的解析错误。另外原有模板存在两个细节问题:
- 模板内的
TextBlock未绑定到父级的Content属性,传入的标签文本不会正常显示 TextBlock上设置的DockPanel.Dock附加属性无效,因为外层容器是StackPanel而非DockPanel,该属性不会生效
实现方案
两种常用实现方式,可根据项目复用需求选择:
方案1:附加属性实现(无需自定义控件,轻量快速)
不需要新建自定义控件,通过WPF附加属性机制扩展ContentControl的属性,用来承载文本框的双向绑定值,改动量最小。
- 先在项目中定义附加属性类:
public static class FormRowAssist { public static readonly DependencyProperty InputValueProperty = DependencyProperty.RegisterAttached( "InputValue", typeof(string), typeof(FormRowAssist), new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault) ); public static void SetInputValue(DependencyObject element, string value) => element.SetValue(InputValueProperty, value); public static string GetInputValue(DependencyObject element) => (string)element.GetValue(InputValueProperty); }
- 修改原有ControlTemplate,补全绑定逻辑:
注意
TemplateBinding是单向(模板父级→模板内控件)的绑定,且对附加属性支持不佳,因此文本框的绑定用RelativeSource定位模板父级,开启双向绑定和输入实时更新
<UserControl.Resources> <ControlTemplate x:Key="formRow" TargetType="ContentControl"> <StackPanel Margin="0 0 0 16"> <!-- 补全标签文本绑定,显示Content传入的字段名称 --> <TextBlock Margin="0 0 0 0" FontWeight="Bold" Text="{TemplateBinding Content}"/> <TextBox Margin="0 8 0 0" Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(local:FormRowAssist.InputValue), Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> </StackPanel> </ControlTemplate> </UserControl.Resources>
- 使用时直接给附加属性赋值/绑定ViewModel即可,不会再触发解析错误:
<ScrollViewer Grid.Row="2" Grid.ColumnSpan="2"> <StackPanel> <ComboBox Width="50" HorizontalAlignment="Left"/> <!-- 测试静态值直接给附加属性赋值即可,对接业务时替换为ViewModel属性绑定 --> <ContentControl x:Name="FITextBox" Content="FI Number: " Template="{StaticResource formRow}" local:FormRowAssist.InputValue="{Binding FiNumber, Mode=TwoWay}"/> </StackPanel> </ScrollViewer>
方案2:自定义表单控件(适合高频复用场景)
如果这类表单项在项目中大量使用,直接自定义继承自ContentControl的专用控件,自带Text依赖属性,使用写法更直观。
- 定义自定义控件后台代码:
public class FormRow : ContentControl { public static readonly DependencyProperty TextProperty = DependencyProperty.Register( nameof(Text), typeof(string), typeof(FormRow), new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault) ); public string Text { get => (string)GetValue(TextProperty); set => SetValue(TextProperty, value); } static FormRow() { DefaultStyleKeyProperty.OverrideMetadata(typeof(FormRow), new FrameworkPropertyMetadata(typeof(FormRow))); } }
- 模板的TargetType改为自定义控件类型,内部可以直接用
TemplateBinding绑定Text属性:
<ControlTemplate x:Key="formRow" TargetType="local:FormRow"> <StackPanel Margin="0 0 0 16"> <TextBlock FontWeight="Bold" Text="{TemplateBinding Content}"/> <TextBox Margin="0 8 0 0" Text="{TemplateBinding Text}"/> </StackPanel> </ControlTemplate>
- 使用时直接实例化自定义控件,和最初预期的写法完全一致:
<local:FormRow Content="FI Number: " Template="{StaticResource formRow}" Text="{Binding FiNumber, Mode=TwoWay}"/>
内容的提问来源于stack exchange,提问作者Brendon Cheung
相关产品推荐
相关产品推荐

