繁体   English   中英

具有自定义控件的Visual Studio WPF UI设计器

[英]Visual Studio WPF UI Designer with Custom Controls

这是一个奇怪的问题:

我有一个自定义控件,该TextBox继承自TextBox ,并提供“ ghost”文本-例如,在框中单击“ Username”,直到您在其中单击,然后“ ghost”文本消失,用户可以在此键入大小写,用户名。

控件的“ Ghost文本”只是TextBox子类中的一个属性。 然后在相关时将TextBox.Text设置为它。

在Visual Studio WPF XAML预览窗口(标准UI设计之一)中,我希望能够“预览”“ Ghost文本”-就像设置文本框的实际文本一样,您可以在预览中看到它。 ,而不只是在运行应用程序时。

我尝试在OnInitialised函数中将Text属性设置为相关的Ghost文本,但是它对预览没有任何影响。

我应该在哪里放置会影响设计器中控件预览的代码?

奖励问题:我所说的“重影”文本框是否有实际名称? 将来会很高兴知道的!

我所谓的“ ghost”文本框是否有实际名称? 将来会成为上帝知道的!

在描述其目的时,我已经将其称为“提示”,而在描述其外观时,则将其称为“水印”。 我倾向于采用前者,因为它描述了功能 ,后者更符合WPF的设计理念:实际的展示方式由模板决定,而概念上的“提示”可以通过应用自定义样式/模板。 为什么当有人可以选择以其他方式展示它时,为什么暗示它应该是水印?

在设计方面,我认为您正在以错误的方式进行处理。 我将实现这种方式,使除TextBox之外的其他TextBox可以更轻松地选择加入:使用附加属性。

我将创建一个静态类,例如HintProperties ,它声明了几个附加的依赖项属性:

  • Hint -声明提示内容; 通常是一个字符串,但不一定要这样。 它可能只是一个object ,类似于ContentControlContent属性。

  • HasHint计算的只读bool属性,当Hint更改时将重新评估该属性,并仅指示控件是否指定了Hint 可用作Trigger条件来切换提示模板在控件模板中的可见性。

然后,为您的TextBox (或其他控件)提供自定义样式,该样式会将Hint覆盖在常规内容的顶部,默认情况下是隐藏的。 当控件具有键盘焦点时,添加一个触发器以减少提示的不透明度;当Text为空字符串时,添加一个触发器以使提示Visible

如果您真的想全力以赴,则可以添加HintTemplateHintTemplateSelector属性。


但是,如果这看起来有些矫kill过正,则可以直接在派生的TextBox类上直接声明HintWatermark属性。 我不会尝试通过有条件地更改Text属性来实现这一点,因为那样会干扰数据绑定以及可能的值优先级。

您可以使用通常在App.xaml声明的样式以可重用的方式执行此操作。 通过这种样式,您可以用自己的实现替换控件模板,并将一些控件包装在一起。 基本上,您是从具有透明背景的普通TextBox组成WatermarkTextBox ,然后在TextBox后面放置一个带有标准文本的TextBlock TextBox TextBlockVisibility使用特定的TextInputToVisibilityConverter绑定到TextBox因此当TextBox具有文本或仅具有焦点时,它将消失。

尽管这可能看起来像很多代码,但您只需定义一次即可,只需设置TextBox样式即可重复使用此代码

声明一些资源

xmlns:c="clr-namespace:YourNameSpace.Converters"
<SolidColorBrush x:Key="brushWatermarkBackground" Color="White" />
<SolidColorBrush x:Key="brushWatermarkForeground" Color="LightSteelBlue" />
<c:TextInputToVisibilityConverter x:Key="TextInputToVisibilityConverter" />

风格宣言:

<Style x:Key="SearchTextBox" TargetType="{x:Type TextBox}">
    <Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
    <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
    <Setter Property="AllowDrop" Value="true"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TextBox}">
                <Grid Background="{StaticResource brushWatermarkBackground}">
                    <TextBlock Margin="5,5" Text="Search..." 
                        Foreground="{StaticResource brushWatermarkForeground}" >
                        <TextBlock.Visibility>
                          <MultiBinding 
                          Converter="{StaticResource TextInputToVisibilityConverter}">
                          <Binding RelativeSource="{RelativeSource 
                                Mode=FindAncestor, AncestorType=TextBox}" 
                                Path="Text.IsEmpty" />
                          <Binding RelativeSource="{RelativeSource 
                              Mode=FindAncestor, AncestorType=TextBox}" 
                              Path="IsFocused" />
                            </MultiBinding>
                        </TextBlock.Visibility>
                    </TextBlock>
                    <Border x:Name="Border" Background="Transparent" 
                       BorderBrush="{DynamicResource SolidBorderBrush}" 
                       BorderThickness="1" Padding="2" CornerRadius="2">

                        <!-- The implementation places the Content into the 
                             ScrollViewer. It must be named PART_ContentHost 
                             for the control to function -->
                        <ScrollViewer Margin="0" x:Name="PART_ContentHost" 
                          Style="{DynamicResource SimpleScrollViewer}" 
                          Background="Transparent"/>
                    </Border>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

仅接受文本输入的TextInputToVisibilityConverter的实现将转换为bool并将其转换为Visibility 同时也要考虑焦点。

namespace YourNameSpace
{
    public class TextInputToVisibilityConverter : IMultiValueConverter
    {
        public object Convert(object[] values, 
              Type targetType, object parameter, 
              System.Globalization.CultureInfo culture)
        {
            if (values[0] is bool && values[1] is bool)
            {
                bool hasText = !(bool)values[0];
                bool hasFocus = (bool)values[1];

                if (hasFocus || hasText)
                    return Visibility.Collapsed;
            }

            return Visibility.Visible;
        }

        public object[] ConvertBack(object value, 
            Type[] targetTypes, object parameter, 
            System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

现在所有基础设施都已就绪。 在视图/用户控件/窗口中,只需更改文本框的样式即可,这里就是您的水印文本框。

<TextBox Style="{DynamicResource SearchTextBox}" />

暂无
暂无

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

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