【问题标题】:Visual Studio WPF UI Designer with Custom Controls带有自定义控件的 Visual Studio WPF UI 设计器
【发布时间】:2014-11-08 06:09:44
【问题描述】:

这是一个有点奇怪的问题:

我有一个继承自 TextBox 的自定义控件,并提供“幽灵”文本 - 例如,它在一个框中显示“用户名”,直到您在其中单击,然后“幽灵”文本消失,用户可以键入在他们的,在这种情况下,用户名。

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

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

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

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

额外问题:我称之为“幽灵”文本框的内容有实际名称吗?将来会很高兴知道!

【问题讨论】:

标签: c# wpf visual-studio-2013


【解决方案1】:

有我称之为“幽灵”文本框的实际名称吗?上帝会知道未来的!

我在描述其用途时将其称为“提示”,在描述其外观时将其称为“水印”。我倾向于使用前者,因为它描述了 function,这更符合 WPF 的设计理念:实际呈现由模板决定,而概念上的“提示”可以以不同的方式呈现只需应用自定义样式/模板。当有人可以选择以其他方式呈现时,为什么暗示它应该是水印?

在设计方面,我认为您以错误的方式处理此问题。我会以这样一种方式实现这一点,即TextBox 以外的控件可以更轻松地选择加入:使用附加属性。

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

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

  • HasHint - 一个计算的、只读的bool 属性,当Hint 更改时会重新计算它,并简单地指示控件是否指定了Hint。可用作Trigger 条件来切换控件模板中提示演示者的可见性。

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

如果你真的想全力以赴,你可以投入HintTemplate和HintTemplateSelector属性。


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

【讨论】:

  • 这听起来确实像一个更灵活的系统 - 但我担心这对于这个项目(个人使用)来说是相当大的杀伤力。不过,如果我找不到更简单的解决方案,我可能会求助于这个:)
  • 好的,我会看看使用带有叠加层的样式 - 它会给我一个借口来了解更多关于样式的知识,我已经忽略了一段时间了!跨度>
  • @hnefatl 同意迈克的观点。代码示例查看第二个答案here on this page with the whopping 230 votes
【解决方案2】:

您可以使用通常在App.xaml 中声明的样式以可重用的方式执行此操作。在这种风格中,您将控件模板替换为您自己的实现并将一些控件包装在一起。基本上,您从具有透明背景的普通TextBox 组成WatermarkTextBox,并在TextBox 后面放置一个带有标准文本的TextBlock 控件。此TextBlock 的Visibility 使用特定的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}" />

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多