【问题标题】:How to display the base control in a WPF custom control如何在 WPF 自定义控件中显示基本控件
【发布时间】:2018-08-24 09:05:14
【问题描述】:

我想扩展一个 TextBox 控件以包含一个 Label,其中 Label 从我的自定义控件的 Label 属性中获取其 Content 并自动附加到 TextBox。 (这是一个用于学习目的的简化示例)。

LabeledTextBox.cs

public class LabeledTextBox : TextBox
{
    static LabeledTextBox() =>
        DefaultStyleKeyProperty.OverrideMetadata(typeof(LabeledTextBox),
            new FrameworkPropertyMetadata(typeof(LabeledTextBox)));

    public static readonly DependencyProperty LabelProperty =
        DependencyProperty.Register("Label", typeof(string), typeof(LabeledTextBox));

    public string Label
    {
        get => (string)GetValue(LabelProperty);
        set => SetValue(LabelProperty, value);
    }
}

主题/Generic.xaml

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:MyExample">

    <Style TargetType="{x:Type local:LabeledTextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:LabeledTextBox}">
                    <StackPanel Orientation="Vertical">
                        <Label Margin="0 0 0 4" Content="{TemplateBinding Label}" Target="{Binding ElementName=tbThis}" />

                        <!-- This doesn't work -->
                        <ContentPresenter x:Name="tbThis" />
                    </StackPanel>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

我不知道如何显示 TextBox 基类。我搜索了 SO 和 Google 中的前几个链接。看起来我应该使用的是&lt;ContentPresenter /&gt;,但它根本没有出现。我还尝试了在 XAML 中设置 ContentPresenter.ContentSource 的几种变体,但均无济于事。

我知道我可以在 ControlTemplate 中添加一个 TextBox,但这意味着要么丢失继承的 TextBox 的所有属性,要么需要手动附加它们,这违背了在 UserControl 上使用自定义控件的全部目的.

【问题讨论】:

    标签: c# wpf xaml


    【解决方案1】:

    只需将Target 绑定到TemplatedParent

    <ControlTemplate TargetType="{x:Type local:LabeledTextBox}">
        <StackPanel>
            <Label Target="{Binding RelativeSource={RelativeSource TemplatedParent}}" Content="{TemplateBinding Label}"/>
            <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
                <ScrollViewer Focusable="False" x:Name="PART_ContentHost" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
            </Border>
        </StackPanel>
    </ControlTemplate>
    

    【讨论】:

    • 为什么是ScrollViewer?仅仅是因为这就是微软设计TextBoxBase 的方式吗?假设我想基于我的LabeledTextBox 创建第二个控件ButtonLabeledTextBox 以包含一个按钮。我还会使用ScrollViewerLabeledTextBox 放在我的ButtonLabeledTextBox 中吗?
    • @dfoverdx Microsoft 使用ScrollViewer 来支持TextBox 中的内容滚动。这取决于您的设计以及您希望ButtonLabledTextBox 的外观和感觉。在这种情况下,您可以在Label 之上添加Button
    【解决方案2】:

    您需要使用PART_ContentHost WPF 魔法访问视觉元素 :)

    这是它的外观:

    <ResourceDictionary
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:MyExample">
    
        <Style TargetType="{x:Type local:LabeledTextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type local:LabeledTextBox}">
                        <StackPanel Orientation="Vertical">
                            <Label Margin="0 0 0 4" Content="{TemplateBinding Label}" Target="{Binding ElementName=tbThis}" />
    
                                    <ScrollViewer x:Name="PART_ContentHost"
                                                  HorizontalAlignment="Stretch"
                                                  VerticalAlignment="Center"
                                                  SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                        </StackPanel>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ResourceDictionary>
    

    【讨论】:

    • 你的意思是Target="{Binding ElementName=PART_ContentHost}" ?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-20
    • 1970-01-01
    • 1970-01-01
    • 2011-08-25
    • 1970-01-01
    相关资源
    最近更新 更多