通过wpf中的内容展示器将公共字符串属性绑定到TextBox文本

时间:2017-07-19 20:05:16

标签: c# wpf xaml mvvm

我创建了一个自定义的wpf控件,希望能够反复使用它来减少编写,复制和粘贴一堆xaml代码所花费的时间。它看起来很简单。它用于Label和TextBox对,所以:

Label here
[  this is the text box (or other control) ]

这样称呼:

<controls:LabeledContentControl Margin="5"
                            MaxHeight="25"
                            LabelText="{Binding LabelString}" 
                            Content="{Binding LabelTextBoxTestString, ValidatesOnNotifyDataErrors=True, UpdateSourceTrigger=PropertyChanged}"/>

<controls:LabeledContentControl Margin="5"
                            LabelText="{Binding LabelString}">
<TextBox Text="{Binding LabelTextBoxTestString, 
                        ValidatesOnNotifyDataErrors=True, 
                        UpdateSourceTrigger=PropertyChanged, 
                        Delay=100}" />
</controls:LabeledContentControl>

LabeledContentControl扩展ContentControl,c#代码似乎不相关,因为它的依赖属性及其setter。与两个构造函数类似,这些构造函数在Microsoft参考文档中实现,用于扩展ContentControl

的其他控件

https://referencesource.microsoft.com/#PresentationFramework/Framework/System/Windows/Controls/HeaderedContentControl.cs

在使用标记内容控件的第一种方法时,我遇到了绑定后备视图模型属性/字段集的问题。

控件的XAML代码如下:

<Style x:Key="{x:Type controls:LabeledContentControl}" TargetType="{x:Type controls:LabeledContentControl}">
<!-- other setters.... -->
<Setter Property="Template">
    <Setter.Value>
        <ControlTemplate TargetType="{x:Type controls:LabeledContentControl}">
            <Border Name="OuterBd" BorderThickness="{TemplateBinding BorderThickness}" >
                <Border Name="InnerBd" Background="{TemplateBinding BorderBrush}" BorderThickness="0">
                    <Border Name="Bd" Background="{TemplateBinding Background}" BorderThickness="0">
                        <DockPanel>
                            <DockPanel DockPanel.Dock="Top" IsHitTestVisible="False">
                                <TextBlock x:Name="FieldRequiredInd" 
                                           Text="* " 
                                           Foreground="Red" 
                                           Visibility="Collapsed"
                                           DockPanel.Dock="Left"/>
                                <TextBlock x:Name="LabelTextBlock"
                                           DockPanel.Dock="Left"
                                           Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=LabelText, Mode=OneWay}" />
                            </DockPanel>

                            <ContentPresenter x:Name="CustomContent" DockPanel.Dock="Bottom" 
                                              Content="{TemplateBinding Content}"
                                              ContentTemplateSelector="{StaticResource LabeledContentControlDataTemplateSelector}"
                                              MaxHeight="{TemplateBinding MaxHeight}"/>
                        </DockPanel>
                    </Border>
                </Border>
            </Border>
            <ControlTemplate.Triggers>
                ...
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </Setter.Value>
</Setter>

模板选择器,同样是超级基本的,如果内容属于string类型使用GetType,则使用字符串的自定义数据窗口,以便它们位于文本框中并可编辑。

<DataTemplate x:Key="StringDataTemplate" DataType="{x:Type system:String}">
    <TextBox>
        <TextBox.Text>
            <Binding Path="." />
        </TextBox.Text>
    </TextBox>
</DataTemplate>

<local:LabeledContentControlDataTemplateSelector x:Key="LabeledContentControlDataTemplateSelector"
                                                 StringDataTemplate="{StaticResource StringDataTemplate}"/>

我如何/可以正确绑定LabelTextBoxTestString ,这样当我在StringDataTemplate生成的文本框中更新/输入内容时,它会更新绑定属性ViewModel?目前,当我使用第一种方法时,当我输入由StringDataTemplate创建的文本框时,后备字段不会使用新内容进行更新,但在使用第二种方法时,后备字段会更新。

1 个答案:

答案 0 :(得分:2)

您需要进行一些修改:

首先是Binding中的正确TextBox.Text

<TextBox.Text>
    <Binding Path="Content" RelativeSource="{RelativeSource TemplatedParent}" UpdateSourceTrigger="PropertyChanged" />
</TextBox.Text>

然后将ContentPresenter的绑定更改为:

<ContentPresenter x:Name="CustomContent"
                  MaxHeight="{TemplateBinding MaxHeight}"
                  Content="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=local:LabeledContentControl}, Path=Content, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                  ContentTemplateSelector="{StaticResource LabeledContentControlDataTemplateSelector}"
                  DockPanel.Dock="Bottom" />

现在你可以绑定你的控件了。请注意,Mode设置为TwoWay Content属性(默认为OneWay),这就是您没有得到反馈的原因:

<controls:LabeledContentControl Margin="5"
                        MaxHeight="25"
                        LabelText="{Binding LabelString}" 
                        Content="{Binding LabelTextBoxTestString, ValidatesOnNotifyDataErrors=True, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>