C# WPF中文本框的焦点相关文本更改

C# WPF中文本框的焦点相关文本更改,c#,.net,wpf,mvvm,textbox,C#,.net,Wpf,Mvvm,Textbox,我正在使用MVVM模式在WPF中编写应用程序,并且经常使用TextBoxes。 我不想使用标签让用户知道文本框的用途,即我不想要这样的东西: <TextBlock> Name: </TextBlock> <TextBox /> <TextBox>Name</TextBox> 如果光标显示在文本框中,即文本框获得焦点,我希望说明文本消失。如果文本框为空且失去焦点,则说明文本应再次显示。它类似于StackOverflow或Firefox

我正在使用MVVM模式在WPF中编写应用程序,并且经常使用
TextBox
es。 我不想使用标签让用户知道文本框的用途,即我不想要这样的东西:

<TextBlock> Name: </TextBlock>
<TextBox />
<TextBox>Name</TextBox>
如果光标显示在文本框中,即
文本框
获得焦点,我希望说明文本消失。如果
文本框
为空且失去焦点,则说明文本应再次显示。它类似于StackOverflow或Firefox的搜索文本框。(如果你不确定我的意思,请告诉我)

一个文本框的标签在运行时可能会更改,具体取决于
组合框的选定元素或my ViewModel中的值。(就像在Firefox的搜索文本框中,如果你从搜索引擎菜单中选择google,文本框的标签会变为“google”,如果你选择“Yahoo”它的设置为“Yahoo”)。因此,我希望能够绑定标签的内容

考虑到我可能已经对
TextBox
Text
-属性进行了绑定

如何实现这样的行为并使其可用于我的任何
文本框
?代码是受欢迎的,但不是必需的;描述一下该做什么就足够了


提前感谢。

您可以从
文本框中派生并实现您的行为。文本框提供了事件
GotFocus
/
LostFocus
(或者分别提供了方法
OnGotFocus
/
OnLostFocus
),应该会有所帮助。您还应该考虑提供一个新的DeDebug属性,这样您就可以定义XAML中的默认文本并将其绑定到其他控件/资源等。

< P>这是一个我认为正是您正在寻找的样式,它是纯XAML。
<Style x:Key="WatermarkTextBox" TargetType="{x:Type TextBox}">
     <Setter Property="Template">
          <Setter.Value>
               <ControlTemplate TargetType="{x:Type TextBox}">
                    <Grid>
                         <Border x:Name="BorderBase" Background="White" BorderThickness="1.4,1.4,1,1" BorderBrush="Silver"> 
                             <Label x:Name="TextPrompt" 
                                Content="{Binding RelativeSource={RelativeSource  Mode=TemplatedParent}, Path=Tag}" 
                                Background="{TemplateBinding Background}" Visibility="Collapsed" 
                                Focusable="False" Foreground="Silver"/>
                         </Border>
                         <ScrollViewer Margin="0" x:Name="PART_ContentHost" Foreground="Black"/>
                    </Grid>
                    <ControlTemplate.Triggers>
                         <MultiTrigger>
                              <MultiTrigger.Conditions>
                                   <Condition Property="IsFocused" Value="False"/>
                                   <Condition Property="Text" Value=""/>
                              </MultiTrigger.Conditions>
                              <Setter Property="Visibility" TargetName="TextPrompt" Value="Visible"/>
                         </MultiTrigger>
                         <Trigger Property="IsFocused" Value="True">
                              <Setter Property="BorderBrush" TargetName="BorderBase" Value="Black"/>
                         </Trigger>
                         <Trigger Property="IsEnabled" Value="False">
                              <Setter Property="Foreground" Value="DimGray" />
                         </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
           </Setter.Value>
      </Setter>
 </Style>

用途是:

<TextBox Style="{StaticResource WatermarkTextBox}" Tag="Full Name"/>

其中标记是要显示的帮助消息

您可以清理此样式以供自己使用,但最重要的部分是控制隐藏/显示辅助文本的控件

同样值得注意的是,已经有一个DependencyObject可用于存储帮助器文本,因此您不需要使用此方法创建自己的

标记可用于保存有关此元素的任意信息。这就是我们设置标记属性的原因:


来详细说明我关于使用装饰物的建议

装饰器基本上是一个元素,在自己的层上渲染,显示在另一个元素的上方/周围。例如,如果在绑定中实现验证,则装饰无效控件的红色框是装饰器-它不是控件的一部分,并且可以(并且是)应用于所有类型的控件。请参阅WPF文档的一节,了解一个简单但清晰的示例

我想到一个装饰品有几个原因。最主要的一点是,您描述的行为不一定局限于
文本框
。例如,您可能希望一个组合框显示相同的行为。实现装饰器将为您提供一种跨多个控件实现此功能的一致方法(尽管在
复选框
进度条
中没有意义)。第二,您不必对底层控件做任何比实现触发器来显示和隐藏装饰器以响应焦点事件更复杂的事情。装饰器的实现有点麻烦,但是知道如何实现它是值得的

综上所述,我喜欢mattjf的答案比我喜欢的多。我认为这种方法的唯一缺点是1)它只适用于
文本框
;每次你想在另一个控件上使用这种方法时,你都需要植入一个新版本的样式。2)我可能只是在进行神奇的思考,但每次我在WinForms中使用
标记
属性时,它都告诉我(一旦我学会了倾听),我正在构建一些脆弱的东西。我不确定这在WPF中是否也是正确的,但我打赌是的

我对使用绑定的
文本
属性的评论可能需要放大。如果使用Text属性存储字段标签,则会遇到许多难以解决的问题。首先,由于它是一个绑定属性,因此在
文本框中更改其值将在源中更改它。因此,现在您的源代码需要了解大量有关UI状态的信息—控件当前是否具有焦点?如果
Text
属性的值是
Foo
,这是否意味着标签是
Foo
,或者用户键入了
Foo
?可能有一些方法可以做到这一点,但最好的方法是不必这样做


(这个范例的另一个问题是:如果用户希望
文本框
的值为空字符串,那么行为应该是什么?

此外,似乎值得研究是否应该将其作为装饰器来实现,这样你就不会对bound
Text
属性胡思乱想了。@Robert:你能解释一下装饰器是什么,是做什么的,以及它如何适应这种情况吗?文本属性可能会出现什么问题?也许你可以写一个答案。。。我会的