WPF自定义文本框控件未正确绑定文本

Sha*_*awn 2 c# data-binding wpf xaml

我有一个自定义TextBox控件.我试图将它绑定到对象的简单描述字符串属性.如何让绑定工作?如果我将其更改为TextBox,相同的绑定工作正常.

<Style x:Key="{x:Type TaskDash:TextBoxWithDescription}" TargetType="{x:Type TaskDash:TextBoxWithDescription}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type TaskDash:TextBoxWithDescription}">

                        <TextBox>
                        </TextBox>

                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
Run Code Online (Sandbox Code Playgroud)
public class TextBoxWithDescription : TextBox
{
    public TextBoxWithDescription()
    {
        LabelText = String.Empty;
    }

    public string LabelText { get; set; }

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        var textBlock = (TextBlock)this.Template.FindName("LabelText", this);
        if (textBlock != null) textBlock.Text = this.LabelText;
    }
}
Run Code Online (Sandbox Code Playgroud)
<TaskDash:TextBoxWithDescription Grid.Row="0" Grid.Column="0"
        x:Name="textBoxDescription" 
        Text="{Binding Description, BindsDirectlyToSource=True}" LabelText="Description">
    </TaskDash:TextBoxWithDescription>
Run Code Online (Sandbox Code Playgroud)
public partial class EditTaskItem : Window
{
    private TaskItem _taskItem;

    public EditTaskItem(TaskItem taskItem)
    {
        InitializeComponent();

        this.DataContext = taskItem;
        textBoxDescription.DataContext = taskItem;
        _taskItem = taskItem;
    }
}
Run Code Online (Sandbox Code Playgroud)

dow*_*for 6

好的......您的代码有一些问题.让我们从您的自定义控件的样式开始.您需要添加一个静态构造函数,以允许重新设置新控件.像这样

    static TextBoxWithDescription ()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(TextBoxWithDescription ), new FrameworkPropertyMetadata(typeof(TextBoxWithDescription )));
    }
Run Code Online (Sandbox Code Playgroud)

这告诉WPF"嘿,请为此控件寻找样式".

现在您可以删除它,x:Key="{x:Type TaskDash:TextBoxWithDescription}"因为这将是您的默认样式.

接下来是.在WPF中,要理解的是,每个控件都绝对没有UI内容,除非它获得模板.您的Style中已经有一个模板,但它获得的唯一可视内容是一个空的TextBox.这很奇怪,因为您从TextBox派生了TextBoxWithDescription.所以你创建的是一个从文本框派生的控件,包含一个文本框.请参阅此内容以查看TextBox模板在WPF 4.0中的外观.

返回ControlTemplate中的空TextBox.请记住,我说,你的控件,没有风格是完全看不见的,它唯一的逻辑.唯一可见的是模板中的TextBox.为了使它以某种方式工作,您需要将一些属性传递给此TextBox.控件说明了如何以及模板获取属性并将其置于使用中.你可以通过TemplateBinding 例如这样做.如果您的控件具有属性背景,则只要您愿意,此属性不会执行任何操作,但ControlTemplate可以为其赋予一些含义.例如,Rectangle在您的中添加一个ControlTemplate并将Fill Property设置为{TemplateBinding Background}.哪个基本告诉Rectangle"你的属性填充将是我们目前模板控件的背景值".我希望这说清楚.

接下来:你覆盖了OnApplyTemplate你通常这样做是为了在你的ControlTemplate中按名称查找一个控件.您似乎将此与您的某个属性混合在一起.要通过FindName在模板中查找控件,您需要为其命名

像这样

<Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type TaskDash:TextBoxWithDescription}">

                        <TextBox x:Name="PART_MyTextBox">
                        </TextBox>

                    </ControlTemplate>
                </Setter.Value>
            </Setter>
Run Code Online (Sandbox Code Playgroud)

并将OnApplyTemplate修改为

var textBlock = (TextBlock)this.Template.FindName("PART_MyTextBox", this);
Run Code Online (Sandbox Code Playgroud)

现在,您在当前的ControlTemplate中拥有了文本块.

我能看到的最后一个错误是.您在OnApplyTemplateTextBox文本中设置LabelText.虽然这有效,但有一次,它不是很好,通常不是WPF方式.此外,如果您修改LabelText属性,它将不会显示,因为您必须再次设置它.将LabelText更改为依赖项属性现在,您可以使用已经提到的TemplateBinding内容直接在控件模板TextBox上设置此文本.

                        <TextBox x:Name="PART_MyTextBox" Text="{TemplateBinding LabelText}>
                        </TextBox>
Run Code Online (Sandbox Code Playgroud)

这还将确保对Control属性的更改也将更新此TextBox上的Text.

最后一件事

this.DataContext = taskItem;
        // textBoxDescription.DataContext = taskItem;
        _taskItem = taskItem;
Run Code Online (Sandbox Code Playgroud)

如果您的textboxdescription将成为窗口的父级,则不需要DataContext显式设置,因为它将在层次结构中继承.只要Element不更改DataContext,它就始终是父元素的DataContext.

我建议你阅读更多关于WPF的基础知识,我知道它有一个陡峭的学习曲线,但它值得努力.如果有人来自WinForms背景,那就很难让所有不同的新设计理念和不同的做事方式得到满足.

希望那有所帮助