繁体   English   中英

如何覆盖自定义 WPF 用户控件的属性

[英]HOWTO override properties from a custom WPF UserControl

我有以下 WPF 用户控件:

<UserControl x:Class="myComponents.UI.TextBoxWithPlaceholder"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:pEp.UI"
             mc:Ignorable="d"
             d:DesignHeight="450" d:DesignWidth="800"
             Loaded="UserControl_Loaded">
    <Grid DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=local:TextBoxWithPlaceholder}}"
          Margin="5">
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <TextBox Name="myCustomTextBox"
                 Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}"
                 Padding="5"
                 IsReadOnly="{Binding IsReadOnly}"
                 HorizontalAlignment="Stretch"
                 TextChanged="CustomTextBox_TextChanged"
                 GotFocus="CustomTextBox_GotFocus"
                 LostFocus="CustomTextBox_LostFocus"
                 Margin="5"
                 HorizontalScrollBarVisibility="Auto"
                 VerticalScrollBarVisibility="Auto" />
        <TextBlock Name="myPlaceholderTextBlock"
                   IsHitTestVisible="False" 
                   Padding="5"
                   Text="{Binding Placeholder}" 
                   HorizontalAlignment="Left" 
                   Foreground="DarkGray"
                   Margin="5">
        </TextBlock>
    </Grid>
</UserControl>

基本上它是一个带有占位符的文本框。

现在,从 WPF 视图,我通过执行以下操作重用此组件:

xmlns:ui="clr-namespace:myComponents.UI"

然后将其作为普通控件放置:

<ui:TextBoxWithPlaceholder Name="myNewTextBox" IsReadOnly="{Binding IsReadOnly}"
                           Style="{StaticResource myTextBoxStyle}"
                           Placeholder="please, enter something here"/>

现在,正如您在上面看到的,我为其设置了自定义样式:

<Style x:Key="myTextBoxStyle" TargetType="{x:Type ui:TextBoxWithPlaceholder}">
    <Setter Property="Margin" Value="0" />
    <Setter Property="Padding" Value="0" />
    <Style.Triggers>
        <Trigger Property="IsFocused" Value="False">
            <Setter Property="Background" Value="{x:Null}"/>
            <Setter Property="Foreground" Value="{x:Null}"/>
            <Setter Property="BorderBrush" Value="{x:Null}"/>
        </Trigger>
    </Style.Triggers>
</Style>

现在在我的“myNewTextBox”控件中,我试图覆盖名为 myCustomTextBox 和 myPlaceholderTextBlock 的控件的一些继承属性,例如 Margin、Padding、Background、Foreground、BorderBrush 等,但我已经尝试了上述样式,但它不起作用。 我也试过:

<Style x:Key="myTextBoxStyle" TargetType="{x:Type ui:TextBoxWithPlaceholder}">
    <Setter Property="{Binding Path=Margin, ElementName=myCustomTextBox}" Value="0" />
    <Setter Property="{Binding Path=Padding, ElementName=myCustomTextBox}" Value="0" />

    <Setter Property="{Binding Path=Margin, ElementName=myPlaceholderTextBlock }" Value="0" />
    <Setter Property="{Binding Path=Padding, ElementName=myPlaceholderTextBlock }" Value="0" />
    <Style.Triggers>
        <Trigger Property="IsFocused" Value="False">
            <Setter Property="{Binding Path=Background, ElementName=myCustomTextBox}" Value="{x:Null}"/>
            <Setter Property="{Binding Path=Foreground, ElementName=myCustomTextBox}" Value="{x:Null}"/>
            <Setter Property="{Binding Path=BorderBrush, ElementName=myCustomTextBox}" Value="{x:Null}"/>
        </Trigger>
    </Style.Triggers>
</Style>

如果您希望能够从使用您的TextBoxWithPlaceholder控件的视图中设置myCustomTextBox的属性,您应该向后者添加依赖属性并在 TextBoxWithPlaceholder.xaml 中绑定到它们并在使用视图中设置它们,例如:

<ui:TextBoxWithPlaceholder ....PlaceHolderMargin="10" />

TextBoxWithPlaceholder.xaml:

<TextBlock Name="myPlaceholderTextBlock"
           ...
           Margin="{Binding PlaceHolderMargin,RelativeSource={RelativeSource AncestorType=UserControl}}">

恐怕您无法从TextBoxWithPlaceholder控件外部的TextBoxWithPlaceholder引用ElementName=myPlaceholderTextBlock ,因此尝试在消费视图中定义的Style中执行此操作是行不通的。

这是一项需要自定义控件和视觉状态而不是带有触发器的UserControl的任务。 但是,如果您必须以UserControl的身份执行此操作(我不怪您,因为在这个阶段要学习很多东西),那么这里是:

首先,当您使用ElementName时,它应该引用 XAML 处理器之前在当前布局的 UI 中已经看到的元素。 不是正在设置样式的控件内的元素。 我认为这种方法行不通。

如果您希望TextBoxWithPlaceholder内的TextBoxTextBlock使用该外部控件的属性,您可以将它们绑定到它,在您的控件的 XAML 内。例如,重写绑定背景的一小部分。

<TextBox Name="myCustomTextBox"
         Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}"
         Background={Binding RelativeSource={RelativeSource.FindAncestor, AncestorType={x:Type ui:TextBoxWithPlaceholder}, Path=Background}}"

但是,如果您真的希望嵌套的 TextBox(“myCustomTextBox”)使用带有触发器的样式及其自己的专用属性值,那么您可能会尝试在您的样式中创建一个Resources部分,该部分本身包含TextBoxTextBlock Something 的隐式 styles像这样

<Style x:Key="myTextBoxStyle" TargetType="{x:Type ui:TextBoxWithPlaceholder}">
    <Style.Resources>
        <!-- Implicit style for TextBox should only apply to TextBoxes inside a TextBoxWithPlaceholder -->
        <Style TargetType="{x:Type TextBox}">
            <Setter Property="Margin" Value="0" />
            <Setter Property="Padding" Value="0" />

            <Style.Triggers>
                <Trigger Property="IsFocused" Value="False">
                    <Setter Property="Background Value="{x:Null}"/>
                    <Setter Property="Foreground" Value="{x:Null}"/>
                    <Setter Property="BorderBrush" Value="{x:Null}"/>
                </Trigger>
            <Style.Triggers>
        </Style>
    </Style.Resources>

</Style>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM