![](/img/trans.png)
[英]Visual Studio 2019 WPF designer won't display custom controls
[英]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
,类似于ContentControl
的Content
属性。
HasHint
计算的只读bool
属性,当Hint
更改时将重新评估该属性,并仅指示控件是否指定了Hint
。 可用作Trigger
条件来切换提示模板在控件模板中的可见性。
然后,为您的TextBox
(或其他控件)提供自定义样式,该样式会将Hint
覆盖在常规内容的顶部,默认情况下是隐藏的。 当控件具有键盘焦点时,添加一个触发器以减少提示的不透明度;当Text
为空字符串时,添加一个触发器以使提示Visible
。
如果您真的想全力以赴,则可以添加HintTemplate
和HintTemplateSelector
属性。
但是,如果这看起来有些矫kill过正,则可以直接在派生的TextBox
类上直接声明Hint
或Watermark
属性。 我不会尝试通过有条件地更改Text
属性来实现这一点,因为那样会干扰数据绑定以及可能的值优先级。
您可以使用通常在App.xaml
声明的样式以可重用的方式执行此操作。 通过这种样式,您可以用自己的实现替换控件模板,并将一些控件包装在一起。 基本上,您是从具有透明背景的普通TextBox
组成WatermarkTextBox
,然后在TextBox
后面放置一个带有标准文本的TextBlock
TextBox
。 此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}" />
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.